Bug 687361: Implement the new IndexedDB setVersion API. r=bent

--HG--
rename : dom/indexedDB/nsIIDBVersionChangeRequest.idl => dom/indexedDB/nsIIDBOpenDBRequest.idl
This commit is contained in:
Kyle Huey 2011-10-20 12:10:56 -04:00
parent c0def581fb
commit 0d874b65fa
88 changed files with 1776 additions and 1299 deletions

View File

@ -646,6 +646,7 @@ GK_ATOM(onbeforepaste, "onbeforepaste")
GK_ATOM(onbeforeprint, "onbeforeprint")
GK_ATOM(onbeforescriptexecute, "onbeforescriptexecute")
GK_ATOM(onbeforeunload, "onbeforeunload")
GK_ATOM(onblocked, "onblocked")
GK_ATOM(onblur, "onblur")
GK_ATOM(onbroadcast, "onbroadcast")
GK_ATOM(onchange, "onchange")
@ -741,6 +742,7 @@ GK_ATOM(ontouchcancel, "ontouchcancel")
GK_ATOM(ontransitionend, "ontransitionend")
GK_ATOM(onunderflow, "onunderflow")
GK_ATOM(onunload, "onunload")
GK_ATOM(onupgradeneeded, "onupgradeneeded")
GK_ATOM(open, "open")
GK_ATOM(optgroup, "optgroup")
GK_ATOM(optimum, "optimum")

View File

@ -95,9 +95,11 @@ DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR, "A mutation operation was at
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR, "A request was placed against a transaction which is currently not active, or which is finished.")
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR, "A request was aborted, for example through a call to IDBTransaction.abort.")
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR, "A mutation operation was attempted in a READ_ONLY transaction.")
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR, "The operation failed because the database was prevented from taking an action. The operation might be able to succeed if the application performs some recovery steps and retries the entire transaction. For example, there was not enough remaining storage space, or the storage quota was reached and the user declined to give more space to the database.")
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TRANSIENT_ERR, "The operation failed because of some temporary problems. The failed operation might be able to succeed when the operation is retried without any intervention by application-level functionality.")
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR, "A lock for the transaction could not be obtained in a reasonable time.")
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR, "The current transaction exceeded its quota limitations.")
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_VERSION_ERR, "The operation failed because the stored database is a higher version than the version requested.")
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR, "The operation failed because the database was prevented from taking an action. The operation might be able to succeed if the application performs some recovery steps and retries the entire transaction. For example, there was not enough remaining storage space, or the storage quota was reached and the user declined to give more space to the database.")
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_DEADLOCK_ERR, "The current transaction was automatically rolled back by the database because of deadlock or other transaction serialization failures.")
/* DOM error codes defined by us */

View File

@ -1505,7 +1505,7 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeRequest, nsDOMGenericSH,
NS_DEFINE_CLASSINFO_DATA(IDBOpenDBRequest, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(IDBDatabaseException, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -4087,8 +4087,8 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(IDBVersionChangeRequest, nsIIDBVersionChangeRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBVersionChangeRequest)
DOM_CLASSINFO_MAP_BEGIN(IDBOpenDBRequest, nsIIDBOpenDBRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBOpenDBRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END

View File

@ -506,7 +506,7 @@ DOMCI_CLASS(IDBCursorWithValue)
DOMCI_CLASS(IDBKeyRange)
DOMCI_CLASS(IDBIndex)
DOMCI_CLASS(IDBVersionChangeEvent)
DOMCI_CLASS(IDBVersionChangeRequest)
DOMCI_CLASS(IDBOpenDBRequest)
DOMCI_CLASS(IDBDatabaseException)
DOMCI_CLASS(Touch)

View File

@ -100,10 +100,12 @@
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,7)
#define NS_ERROR_DOM_INDEXEDDB_ABORT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,8)
#define NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,9)
#define NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,10)
#define NS_ERROR_DOM_INDEXEDDB_TRANSIENT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,11)
#define NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,12)
#define NS_ERROR_DOM_INDEXEDDB_DEADLOCK_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,13)
#define NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,10)
#define NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,11)
#define NS_ERROR_DOM_INDEXEDDB_VERSION_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,12)
#define NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,1001)
#define NS_ERROR_DOM_INDEXEDDB_DEADLOCK_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,1002)
/* DOM error codes defined by us */

View File

@ -120,10 +120,31 @@ ConvertCloneBuffersToArrayInternal(
} // anonymous namespace
nsresult
HelperBase::WrapNative(JSContext* aCx,
nsISupports* aNative,
jsval* aResult)
{
NS_ASSERTION(aCx, "Null context!");
NS_ASSERTION(aNative, "Null pointer!");
NS_ASSERTION(aResult, "Null pointer!");
NS_ASSERTION(mRequest, "Null request!");
JSObject* global =
static_cast<JSObject*>(mRequest->ScriptContext()->GetNativeGlobal());
NS_ENSURE_TRUE(global, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsresult rv =
nsContentUtils::WrapNative(aCx, global, aNative, aResult);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return NS_OK;
}
AsyncConnectionHelper::AsyncConnectionHelper(IDBDatabase* aDatabase,
IDBRequest* aRequest)
: mDatabase(aDatabase),
mRequest(aRequest),
: HelperBase(aRequest),
mDatabase(aDatabase),
mTimeoutDuration(TimeDuration::FromMilliseconds(kDefaultTimeoutMS)),
mResultCode(NS_OK),
mDispatched(false)
@ -133,9 +154,9 @@ AsyncConnectionHelper::AsyncConnectionHelper(IDBDatabase* aDatabase,
AsyncConnectionHelper::AsyncConnectionHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest)
: mDatabase(aTransaction->mDatabase),
: HelperBase(aRequest),
mDatabase(aTransaction->mDatabase),
mTransaction(aTransaction),
mRequest(aRequest),
mTimeoutDuration(TimeDuration::FromMilliseconds(kDefaultTimeoutMS)),
mResultCode(NS_OK),
mDispatched(false)
@ -195,7 +216,7 @@ AsyncConnectionHelper::Run()
gCurrentTransaction = mTransaction;
if (mRequest) {
nsresult rv = mRequest->SetDone(this);
nsresult rv = mRequest->NotifyHelperCompleted(this);
if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
mResultCode = rv;
}
@ -379,14 +400,19 @@ AsyncConnectionHelper::Init()
return NS_OK;
}
already_AddRefed<nsDOMEvent>
AsyncConnectionHelper::CreateSuccessEvent()
{
return CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR));
}
nsresult
AsyncConnectionHelper::OnSuccess()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(mRequest, "Null request!");
nsRefPtr<nsDOMEvent> event =
CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR));
nsRefPtr<nsDOMEvent> event = CreateSuccessEvent();
if (!event) {
NS_ERROR("Failed to create event!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@ -468,27 +494,6 @@ AsyncConnectionHelper::ReleaseMainThreadObjects()
mRequest = nsnull;
}
nsresult
AsyncConnectionHelper::WrapNative(JSContext* aCx,
nsISupports* aNative,
jsval* aResult)
{
NS_ASSERTION(aCx, "Null context!");
NS_ASSERTION(aNative, "Null pointer!");
NS_ASSERTION(aResult, "Null pointer!");
NS_ASSERTION(mRequest, "Null request!");
JSObject* global =
static_cast<JSObject*>(mRequest->ScriptContext()->GetNativeGlobal());
NS_ENSURE_TRUE(global, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsresult rv =
nsContentUtils::WrapNative(aCx, global, aNative, aResult);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return NS_OK;
}
// static
nsresult
AsyncConnectionHelper::ConvertCloneBuffersToArray(

View File

@ -49,6 +49,8 @@
#include "nsIRunnable.h"
#include "nsIThread.h"
#include "nsDOMEvent.h"
#include "mozilla/TimeStamp.h"
class mozIStorageConnection;
@ -57,6 +59,33 @@ BEGIN_INDEXEDDB_NAMESPACE
class IDBTransaction;
// A common base class for AsyncConnectionHelper and OpenDatabaseHelper that
// IDBRequest can use.
class HelperBase : public nsIRunnable
{
friend class IDBRequest;
public:
virtual nsresult GetResultCode() = 0;
virtual nsresult GetSuccessResult(JSContext* aCx,
jsval* aVal) = 0;
protected:
HelperBase(IDBRequest* aRequest)
: mRequest(aRequest)
{ }
/**
* Helper to wrap a native into a jsval. Uses the global object of the request
* to parent the native.
*/
nsresult WrapNative(JSContext* aCx,
nsISupports* aNative,
jsval* aResult);
nsRefPtr<IDBRequest> mRequest;
};
/**
* Must be subclassed. The subclass must implement DoDatabaseWork. It may then
* choose to implement OnSuccess and OnError depending on the needs of the
@ -66,11 +95,9 @@ class IDBTransaction;
* and Dispatched from the main thread only. Target thread may not be the main
* thread.
*/
class AsyncConnectionHelper : public nsIRunnable,
class AsyncConnectionHelper : public HelperBase,
public mozIStorageProgressHandler
{
friend class IDBRequest;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
@ -128,6 +155,13 @@ protected:
*/
virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) = 0;
/**
* This function returns the event to be dispatched at the request when
* OnSuccess is called. A subclass can override this to fire an event other
* than "success" at the request.
*/
virtual already_AddRefed<nsDOMEvent> CreateSuccessEvent();
/**
* This callback is run on the main thread if DoDatabaseWork returned NS_OK.
* The default implementation fires a "success" DOM event with its target set
@ -157,14 +191,6 @@ protected:
*/
virtual void ReleaseMainThreadObjects();
/**
* Helper to wrap a native into a jsval. Uses the global object of the request
* to parent the native.
*/
nsresult WrapNative(JSContext* aCx,
nsISupports* aNative,
jsval* aResult);
/**
* Helper to make a JS array object out of an array of clone buffers.
*/
@ -176,7 +202,6 @@ protected:
protected:
nsRefPtr<IDBDatabase> mDatabase;
nsRefPtr<IDBTransaction> mTransaction;
nsRefPtr<IDBRequest> mRequest;
private:
nsCOMPtr<mozIStorageProgressHandler> mOldProgressHandler;

View File

@ -150,7 +150,7 @@ CheckPermissionsHelper::Run()
return NS_OK;
}
nsRefPtr<AsyncConnectionHelper> helper;
nsRefPtr<OpenDatabaseHelper> helper;
helper.swap(mHelper);
nsCOMPtr<nsIDOMWindow> window;
@ -168,7 +168,8 @@ CheckPermissionsHelper::Run()
"Unknown permission!");
helper->SetError(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return helper->Run();
return helper->RunImmediately();
}
NS_IMETHODIMP

View File

@ -41,7 +41,7 @@
#define mozilla_dom_indexeddb_checkpermissionshelper_h__
// Only meant to be included in IndexedDB source files, not exported.
#include "AsyncConnectionHelper.h"
#include "OpenDatabaseHelper.h"
#include "nsIInterfaceRequestor.h"
#include "nsIObserver.h"
@ -62,7 +62,7 @@ public:
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIOBSERVER
CheckPermissionsHelper(AsyncConnectionHelper* aHelper,
CheckPermissionsHelper(OpenDatabaseHelper* aHelper,
nsIDOMWindow* aWindow,
const nsAString& aName,
const nsACString& aASCIIOrigin)
@ -80,7 +80,7 @@ public:
}
private:
nsRefPtr<AsyncConnectionHelper> mHelper;
nsRefPtr<OpenDatabaseHelper> mHelper;
nsCOMPtr<nsIDOMWindow> mWindow;
nsString mName;
nsCString mASCIIOrigin;

View File

@ -68,7 +68,7 @@ struct DatabaseInfo
bool ContainsStoreName(const nsAString& aName);
nsString name;
nsString version;
PRUint64 version;
PRUint32 id;
nsString filePath;
PRInt64 nextObjectStoreId;

View File

@ -72,24 +72,6 @@ mozilla::Mutex* gPromptHelpersMutex = nsnull;
// Protected by gPromptHelpersMutex.
nsTArray<nsRefPtr<CheckQuotaHelper> >* gPromptHelpers = nsnull;
class SetVersionHelper : public AsyncConnectionHelper
{
public:
SetVersionHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
const nsAString& aVersion)
: AsyncConnectionHelper(aTransaction, aRequest), mVersion(aVersion)
{ }
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
nsresult GetSuccessResult(JSContext* aCx,
jsval* aVal);
private:
// In-params
nsString mVersion;
};
class CreateObjectStoreHelper : public AsyncConnectionHelper
{
public:
@ -502,14 +484,14 @@ IDBDatabase::GetName(nsAString& aName)
}
NS_IMETHODIMP
IDBDatabase::GetVersion(nsAString& aVersion)
IDBDatabase::GetVersion(PRUint64* aVersion)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabaseId, &info)) {
NS_ERROR("This should never fail!");
}
aVersion.Assign(info->version);
*aVersion = info->version;
return NS_OK;
}
@ -687,48 +669,6 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName)
return NS_OK;
}
NS_IMETHODIMP
IDBDatabase::SetVersion(const nsAString& aVersion,
JSContext* aCx,
nsIIDBRequest** _retval)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mClosed) {
// XXX Update spec for a real error code here.
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
}
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabaseId, &info)) {
NS_ERROR("This should never fail!");
}
// Lock the whole database.
nsTArray<nsString> storesToOpen;
nsRefPtr<IDBTransaction> transaction =
IDBTransaction::Create(this, storesToOpen, IDBTransaction::VERSION_CHANGE,
kDefaultDatabaseTimeoutSeconds, true);
NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<IDBVersionChangeRequest> request =
IDBVersionChangeRequest::Create(static_cast<nsIDOMEventTarget*>(this),
ScriptContext(), Owner(), transaction);
NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<SetVersionHelper> helper =
new SetVersionHelper(transaction, request, aVersion);
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
nsresult rv = mgr->SetDatabaseVersion(this, request, aVersion, helper);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
request.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
IDBDatabase::Transaction(nsIVariant* aStoreNames,
PRUint16 aMode,
@ -933,47 +873,6 @@ IDBDatabase::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
return NS_OK;
}
nsresult
SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
NS_PRECONDITION(aConnection, "Passing a null connection!");
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE database "
"SET version = :version"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("version"), mVersion);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (NS_FAILED(stmt->Execute())) {
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
}
return NS_OK;
}
nsresult
SetVersionHelper::GetSuccessResult(JSContext* aCx,
jsval* aVal)
{
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabase->Id(), &info)) {
NS_ERROR("This should never fail!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
info->version = mVersion;
nsresult rv = WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*,
mTransaction),
aVal);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{

View File

@ -103,9 +103,10 @@ mozilla::dom::indexedDB::CreateGenericEventRunnable(const nsAString& aType,
}
// static
already_AddRefed<nsIDOMEvent>
already_AddRefed<nsDOMEvent>
IDBVersionChangeEvent::CreateInternal(const nsAString& aType,
const nsAString& aVersion)
PRUint64 aOldVersion,
PRUint64 aNewVersion)
{
nsRefPtr<IDBVersionChangeEvent> event(new IDBVersionChangeEvent());
@ -115,7 +116,8 @@ IDBVersionChangeEvent::CreateInternal(const nsAString& aType,
rv = event->SetTrusted(true);
NS_ENSURE_SUCCESS(rv, nsnull);
event->mVersion = aVersion;
event->mOldVersion = aOldVersion;
event->mNewVersion = aNewVersion;
nsDOMEvent* result;
event.forget(&result);
@ -125,10 +127,12 @@ IDBVersionChangeEvent::CreateInternal(const nsAString& aType,
// static
already_AddRefed<nsIRunnable>
IDBVersionChangeEvent::CreateRunnableInternal(const nsAString& aType,
const nsAString& aVersion,
PRUint64 aOldVersion,
PRUint64 aNewVersion,
nsIDOMEventTarget* aTarget)
{
nsCOMPtr<nsIDOMEvent> event = CreateInternal(aType, aVersion);
nsRefPtr<nsDOMEvent> event =
CreateInternal(aType, aOldVersion, aNewVersion);
NS_ENSURE_TRUE(event, nsnull);
nsCOMPtr<nsIRunnable> runnable(new EventFiringRunnable(aTarget, event));
@ -146,8 +150,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
DOMCI_DATA(IDBVersionChangeEvent, IDBVersionChangeEvent)
NS_IMETHODIMP
IDBVersionChangeEvent::GetVersion(nsAString& aVersion)
IDBVersionChangeEvent::GetOldVersion(PRUint64* aOldVersion)
{
aVersion.Assign(mVersion);
NS_ENSURE_ARG_POINTER(aOldVersion);
*aOldVersion = mOldVersion;
return NS_OK;
}
NS_IMETHODIMP
IDBVersionChangeEvent::GetNewVersion(PRUint64* aNewVersion)
{
NS_ENSURE_ARG_POINTER(aNewVersion);
*aNewVersion = mNewVersion;
return NS_OK;
}

View File

@ -56,6 +56,7 @@
#define TIMEOUT_EVT_STR "timeout"
#define VERSIONCHANGE_EVT_STR "versionchange"
#define BLOCKED_EVT_STR "blocked"
#define UPGRADENEEDED_EVT_STR "upgradeneeded"
BEGIN_INDEXEDDB_NAMESPACE
@ -75,48 +76,65 @@ public:
NS_FORWARD_TO_NSDOMEVENT
NS_DECL_NSIIDBVERSIONCHANGEEVENT
inline static already_AddRefed<nsIDOMEvent>
Create(const nsAString& aVersion)
inline static already_AddRefed<nsDOMEvent>
Create(PRInt64 aOldVersion,
PRInt64 aNewVersion)
{
return CreateInternal(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR), aVersion);
return CreateInternal(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR),
aOldVersion, aNewVersion);
}
inline static already_AddRefed<nsIDOMEvent>
CreateBlocked(const nsAString& aVersion)
inline static already_AddRefed<nsDOMEvent>
CreateBlocked(PRUint64 aOldVersion,
PRUint64 aNewVersion)
{
return CreateInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR), aVersion);
return CreateInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR),
aOldVersion, aNewVersion);
}
inline static already_AddRefed<nsDOMEvent>
CreateUpgradeNeeded(PRUint64 aOldVersion,
PRUint64 aNewVersion)
{
return CreateInternal(NS_LITERAL_STRING(UPGRADENEEDED_EVT_STR),
aOldVersion, aNewVersion);
}
inline static already_AddRefed<nsIRunnable>
CreateRunnable(const nsAString& aVersion,
CreateRunnable(PRUint64 aOldVersion,
PRUint64 aNewVersion,
nsIDOMEventTarget* aTarget)
{
return CreateRunnableInternal(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR),
aVersion, aTarget);
aOldVersion, aNewVersion, aTarget);
}
static already_AddRefed<nsIRunnable>
CreateBlockedRunnable(const nsAString& aVersion,
CreateBlockedRunnable(PRUint64 aOldVersion,
PRUint64 aNewVersion,
nsIDOMEventTarget* aTarget)
{
return CreateRunnableInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR), aVersion,
aTarget);
return CreateRunnableInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR),
aOldVersion, aNewVersion, aTarget);
}
protected:
IDBVersionChangeEvent() : nsDOMEvent(nsnull, nsnull) { }
virtual ~IDBVersionChangeEvent() { }
static already_AddRefed<nsIDOMEvent>
static already_AddRefed<nsDOMEvent>
CreateInternal(const nsAString& aType,
const nsAString& aVersion);
PRUint64 aOldVersion,
PRUint64 aNewVersion);
static already_AddRefed<nsIRunnable>
CreateRunnableInternal(const nsAString& aType,
const nsAString& aVersion,
PRUint64 aOldVersion,
PRUint64 aNewVersion,
nsIDOMEventTarget* aTarget);
nsString mVersion;
PRUint64 mOldVersion;
PRUint64 mNewVersion;
};
END_INDEXEDDB_NAMESPACE

View File

@ -53,7 +53,6 @@
#include "nsDirectoryServiceUtils.h"
#include "nsDOMClassInfoID.h"
#include "nsIPrincipal.h"
#include "nsEscape.h"
#include "nsHashKeys.h"
#include "nsPIDOMWindow.h"
#include "nsServiceManagerUtils.h"
@ -65,6 +64,7 @@
#include "CheckPermissionsHelper.h"
#include "DatabaseInfo.h"
#include "IDBDatabase.h"
#include "IDBEvents.h"
#include "IDBKeyRange.h"
#include "IndexedDatabaseManager.h"
#include "LazyIdleThread.h"
@ -72,8 +72,6 @@
using namespace mozilla;
#define DB_SCHEMA_VERSION 4
USING_INDEXEDDB_NAMESPACE
namespace {
@ -89,360 +87,6 @@ struct ObjectStoreInfoMap
ObjectStoreInfo* info;
};
class OpenDatabaseHelper : public AsyncConnectionHelper
{
public:
OpenDatabaseHelper(IDBRequest* aRequest,
const nsAString& aName,
const nsACString& aASCIIOrigin)
: AsyncConnectionHelper(static_cast<IDBDatabase*>(nsnull), aRequest),
mName(aName), mASCIIOrigin(aASCIIOrigin), mDatabaseId(0),
mLastObjectStoreId(0), mLastIndexId(0)
{ }
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
nsresult GetSuccessResult(JSContext* aCx,
jsval* aVal);
private:
// In-params.
nsString mName;
nsCString mASCIIOrigin;
// Out-params.
nsTArray<nsAutoPtr<ObjectStoreInfo> > mObjectStores;
nsString mVersion;
PRUint32 mDataVersion;
nsString mDatabaseFilePath;
PRUint32 mDatabaseId;
PRInt64 mLastObjectStoreId;
PRInt64 mLastIndexId;
};
nsresult
CreateTables(mozIStorageConnection* aDBConn)
{
NS_PRECONDITION(!NS_IsMainThread(),
"Creating tables on the main thread!");
NS_PRECONDITION(aDBConn, "Passing a null database connection!");
// Table `database`
nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE database ("
"name TEXT NOT NULL, "
"version TEXT DEFAULT NULL, "
"dataVersion INTEGER NOT NULL"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `object_store`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_store ("
"id INTEGER, "
"name TEXT NOT NULL, "
"key_path TEXT NOT NULL, "
"auto_increment INTEGER NOT NULL DEFAULT 0, "
"PRIMARY KEY (id), "
"UNIQUE (name)"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `object_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_data ("
"id INTEGER, "
"object_store_id INTEGER NOT NULL, "
"data BLOB NOT NULL, "
"key_value DEFAULT NULL, " // NONE affinity
"PRIMARY KEY (id), "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE UNIQUE INDEX key_index "
"ON object_data (key_value, object_store_id);"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `ai_object_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE ai_object_data ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"object_store_id INTEGER NOT NULL, "
"data BLOB NOT NULL, "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE UNIQUE INDEX ai_key_index "
"ON ai_object_data (id, object_store_id);"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `index`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_store_index ("
"id INTEGER, "
"object_store_id INTEGER NOT NULL, "
"name TEXT NOT NULL, "
"key_path TEXT NOT NULL, "
"unique_index INTEGER NOT NULL, "
"object_store_autoincrement INTERGER NOT NULL, "
"PRIMARY KEY (id), "
"UNIQUE (object_store_id, name), "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE index_data ("
"id INTEGER, "
"index_id INTEGER NOT NULL, "
"object_data_id INTEGER NOT NULL, "
"object_data_key NOT NULL, " // NONE affinity
"value NOT NULL, "
"PRIMARY KEY (id), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE, "
"FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX value_index "
"ON index_data (index_id, value);"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `unique_index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE unique_index_data ("
"id INTEGER, "
"index_id INTEGER NOT NULL, "
"object_data_id INTEGER NOT NULL, "
"object_data_key NOT NULL, " // NONE affinity
"value NOT NULL, "
"PRIMARY KEY (id), "
"UNIQUE (index_id, value), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE "
"FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `ai_index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE ai_index_data ("
"id INTEGER, "
"index_id INTEGER NOT NULL, "
"ai_object_data_id INTEGER NOT NULL, "
"value NOT NULL, "
"PRIMARY KEY (id), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE, "
"FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX ai_value_index "
"ON ai_index_data (index_id, value);"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `ai_unique_index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE ai_unique_index_data ("
"id INTEGER, "
"index_id INTEGER NOT NULL, "
"ai_object_data_id INTEGER NOT NULL, "
"value NOT NULL, "
"PRIMARY KEY (id), "
"UNIQUE (index_id, value), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE, "
"FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->SetSchemaVersion(DB_SCHEMA_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
CreateMetaData(mozIStorageConnection* aConnection,
const nsAString& aName)
{
NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
NS_PRECONDITION(aConnection, "Null database!");
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"INSERT OR REPLACE INTO database (name, dataVersion) "
"VALUES (:name, :dataVersion)"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("dataVersion"),
JS_STRUCTURED_CLONE_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
return stmt->Execute();
}
nsresult
GetDatabaseFile(const nsACString& aASCIIOrigin,
const nsAString& aName,
nsIFile** aDatabaseFile)
{
NS_ASSERTION(!aASCIIOrigin.IsEmpty() && !aName.IsEmpty(), "Bad arguments!");
nsCOMPtr<nsIFile> dbFile;
nsresult rv = IDBFactory::GetDirectory(getter_AddRefs(dbFile));
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin);
originSanitized.ReplaceChar(":/", '+');
rv = dbFile->Append(originSanitized);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString filename;
filename.AppendInt(HashString(aName));
nsCString escapedName;
if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) {
NS_WARNING("Can't escape database name!");
return NS_ERROR_UNEXPECTED;
}
const char* forwardIter = escapedName.BeginReading();
const char* backwardIter = escapedName.EndReading() - 1;
nsCString substring;
while (forwardIter <= backwardIter && substring.Length() < 21) {
if (substring.Length() % 2) {
substring.Append(*backwardIter--);
}
else {
substring.Append(*forwardIter++);
}
}
filename.Append(NS_ConvertASCIItoUTF16(substring));
filename.AppendLiteral(".sqlite");
rv = dbFile->Append(filename);
NS_ENSURE_SUCCESS(rv, rv);
dbFile.forget(aDatabaseFile);
return NS_OK;
}
nsresult
CreateDatabaseConnection(const nsAString& aName,
nsIFile* aDBFile,
mozIStorageConnection** aConnection)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsCOMPtr<nsIFile> dbDirectory;
nsresult rv = aDBFile->GetParent(getter_AddRefs(dbDirectory));
NS_ENSURE_SUCCESS(rv, rv);
bool exists;
rv = aDBFile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota");
nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
nsCOMPtr<mozIStorageConnection> connection;
rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
getter_AddRefs(connection));
if (rv == NS_ERROR_FILE_CORRUPTED) {
// Nuke the database file. The web services can recreate their data.
rv = aDBFile->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
exists = false;
rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
getter_AddRefs(connection));
}
NS_ENSURE_SUCCESS(rv, rv);
// Check to make sure that the database schema is correct.
PRInt32 schemaVersion;
rv = connection->GetSchemaVersion(&schemaVersion);
NS_ENSURE_SUCCESS(rv, rv);
if (schemaVersion != DB_SCHEMA_VERSION) {
if (exists) {
// If the connection is not at the right schema version, nuke it.
rv = aDBFile->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
getter_AddRefs(connection));
NS_ENSURE_SUCCESS(rv, rv);
}
mozStorageTransaction transaction(connection, false,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
rv = CreateTables(connection);
NS_ENSURE_SUCCESS(rv, rv);
rv = CreateMetaData(connection, aName);
NS_ENSURE_SUCCESS(rv, rv);
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
}
// Check to make sure that the database schema is correct again.
NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) &&
schemaVersion == DB_SCHEMA_VERSION,
"CreateTables failed!");
// Turn on foreign key constraints.
rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"PRAGMA foreign_keys = ON;"
));
NS_ENSURE_SUCCESS(rv, rv);
connection.forget(aConnection);
return NS_OK;
}
} // anonymous namespace
IDBFactory::IDBFactory()
@ -571,13 +215,12 @@ IDBFactory::GetDirectoryForOrigin(const nsACString& aASCIIOrigin,
nsresult
IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
PRUint32 aDatabaseId,
nsAString& aVersion,
PRUint64* aVersion,
ObjectStoreInfoArray& aObjectStores)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aConnection, "Null pointer!");
aVersion.Truncate();
aObjectStores.Clear();
// Load object store names and ids.
@ -672,21 +315,18 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
return NS_ERROR_UNEXPECTED;
}
nsString version;
rv = stmt->GetString(0, version);
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 version = 0;
rv = stmt->GetInt64(0, &version);
if (version.IsVoid()) {
version.SetIsVoid(false);
}
aVersion = version;
return NS_OK;
*aVersion = NS_MAX<PRInt64>(version, 0);
return rv;
}
// static
nsresult
IDBFactory::UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
const nsAString& aVersion,
PRUint64 aVersion,
ObjectStoreInfoArray& aObjectStores)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -739,11 +379,16 @@ DOMCI_DATA(IDBFactory, IDBFactory)
NS_IMETHODIMP
IDBFactory::Open(const nsAString& aName,
PRInt64 aVersion,
JSContext* aCx,
nsIIDBRequest** _retval)
nsIIDBOpenDBRequest** _retval)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (aVersion < 1) {
return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
}
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// Force ContentChild to cache the path from the parent, so that
// we do not end up in a side thread that asks for the path (which
@ -784,12 +429,12 @@ IDBFactory::Open(const nsAString& aName,
}
}
nsRefPtr<IDBRequest> request = IDBRequest::Create(this, context, window,
nsnull);
nsRefPtr<IDBOpenDBRequest> request =
IDBOpenDBRequest::Create(context, window);
NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<OpenDatabaseHelper> openHelper =
new OpenDatabaseHelper(request, aName, origin);
new OpenDatabaseHelper(request, aName, origin, aVersion);
nsRefPtr<CheckPermissionsHelper> permissionHelper =
new CheckPermissionsHelper(openHelper, window, aName, origin);
@ -803,200 +448,3 @@ IDBFactory::Open(const nsAString& aName,
request.forget(_retval);
return NS_OK;
}
nsresult
OpenDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
#ifdef DEBUG
{
bool correctThread;
NS_ASSERTION(NS_SUCCEEDED(IndexedDatabaseManager::Get()->IOThread()->
IsOnCurrentThread(&correctThread)) &&
correctThread,
"Running on the wrong thread!");
}
#endif
NS_ASSERTION(!aConnection, "Huh?!");
if (IndexedDatabaseManager::IsShuttingDown()) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsCOMPtr<nsIFile> dbFile;
nsresult rv = GetDatabaseFile(mASCIIOrigin, mName, getter_AddRefs(dbFile));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = dbFile->GetPath(mDatabaseFilePath);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsCOMPtr<nsIFile> dbDirectory;
rv = dbFile->GetParent(getter_AddRefs(dbDirectory));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
bool exists;
rv = dbDirectory->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (exists) {
bool isDirectory;
rv = dbDirectory->IsDirectory(&isDirectory);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
else {
rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
rv = mgr->EnsureQuotaManagementForDirectory(dbDirectory);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsCOMPtr<mozIStorageConnection> connection;
rv = CreateDatabaseConnection(mName, dbFile, getter_AddRefs(connection));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
// Get the data version.
nsCOMPtr<mozIStorageStatement> stmt;
rv = connection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT dataVersion "
"FROM database"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
bool hasResult;
rv = stmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (!hasResult) {
NS_ERROR("Database has no dataVersion!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
PRInt64 dataVersion;
rv = stmt->GetInt64(0, &dataVersion);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (dataVersion > JS_STRUCTURED_CLONE_VERSION) {
NS_ERROR("Bad data version!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
if (dataVersion < JS_STRUCTURED_CLONE_VERSION) {
// Need to upgrade the database, here, before returning to the main thread.
NS_NOTYETIMPLEMENTED("Implement me!");
}
mDatabaseId = HashString(mDatabaseFilePath);
NS_ASSERTION(mDatabaseId, "HashString gave us 0?!");
rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId, mVersion,
mObjectStores);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
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 = NS_MAX(indexInfo.id, mLastIndexId);
}
mLastObjectStoreId = NS_MAX(objectStoreInfo->id, mLastObjectStoreId);
}
return NS_OK;
}
nsresult
OpenDatabaseHelper::GetSuccessResult(JSContext* aCx,
jsval *aVal)
{
DatabaseInfo* dbInfo;
if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
NS_ASSERTION(dbInfo->referenceCount, "Bad reference count!");
++dbInfo->referenceCount;
#ifdef DEBUG
{
NS_ASSERTION(dbInfo->name == mName &&
dbInfo->version == mVersion &&
dbInfo->id == mDatabaseId &&
dbInfo->filePath == mDatabaseFilePath,
"Metadata mismatch!");
PRUint32 objectStoreCount = mObjectStores.Length();
for (PRUint32 index = 0; index < objectStoreCount; index++) {
nsAutoPtr<ObjectStoreInfo>& info = mObjectStores[index];
NS_ASSERTION(info->databaseId == mDatabaseId, "Huh?!");
ObjectStoreInfo* otherInfo;
NS_ASSERTION(ObjectStoreInfo::Get(mDatabaseId, info->name, &otherInfo),
"ObjectStore not known!");
NS_ASSERTION(info->name == otherInfo->name &&
info->id == otherInfo->id &&
info->keyPath == otherInfo->keyPath &&
info->autoIncrement == otherInfo->autoIncrement &&
info->databaseId == otherInfo->databaseId,
"Metadata mismatch!");
NS_ASSERTION(dbInfo->ContainsStoreName(info->name),
"Object store names out of date!");
NS_ASSERTION(info->indexes.Length() == otherInfo->indexes.Length(),
"Bad index length!");
PRUint32 indexCount = info->indexes.Length();
for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) {
const IndexInfo& indexInfo = info->indexes[indexIndex];
const IndexInfo& otherIndexInfo = otherInfo->indexes[indexIndex];
NS_ASSERTION(indexInfo.id == otherIndexInfo.id,
"Bad index id!");
NS_ASSERTION(indexInfo.name == otherIndexInfo.name,
"Bad index name!");
NS_ASSERTION(indexInfo.keyPath == otherIndexInfo.keyPath,
"Bad index keyPath!");
NS_ASSERTION(indexInfo.unique == otherIndexInfo.unique,
"Bad index unique value!");
NS_ASSERTION(indexInfo.autoIncrement == otherIndexInfo.autoIncrement,
"Bad index autoIncrement value!");
}
}
}
#endif
}
else {
nsAutoPtr<DatabaseInfo> newInfo(new DatabaseInfo());
newInfo->name = mName;
newInfo->id = mDatabaseId;
newInfo->filePath = mDatabaseFilePath;
newInfo->referenceCount = 1;
if (!DatabaseInfo::Put(newInfo)) {
NS_ERROR("Failed to add to hash!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
dbInfo = newInfo.forget();
nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mVersion,
mObjectStores);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!");
}
dbInfo->nextObjectStoreId = mLastObjectStoreId + 1;
dbInfo->nextIndexId = mLastIndexId + 1;
nsRefPtr<IDBDatabase> database =
IDBDatabase::Create(mRequest->ScriptContext(), mRequest->Owner(), dbInfo,
mASCIIOrigin);
if (!database) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, database),
aVal);
}

View File

@ -85,12 +85,12 @@ public:
static nsresult
LoadDatabaseInformation(mozIStorageConnection* aConnection,
PRUint32 aDatabaseId,
nsAString& aVersion,
PRUint64* aVersion,
ObjectStoreInfoArray& aObjectStores);
static nsresult
UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
const nsAString& aVersion,
PRUint64 aVersion,
ObjectStoreInfoArray& aObjectStores);
private:

View File

@ -121,7 +121,7 @@ IDBRequest::Reset()
}
nsresult
IDBRequest::SetDone(AsyncConnectionHelper* aHelper)
IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
@ -203,12 +203,10 @@ IDBRequest::GetReadyState(PRUint16* aReadyState)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mHaveResultOrErrorCode) {
*aReadyState = nsIIDBRequest::DONE;
}
else {
*aReadyState = nsIIDBRequest::LOADING;
}
*aReadyState = mHaveResultOrErrorCode ?
nsIIDBRequest::DONE :
nsIIDBRequest::LOADING;
return NS_OK;
}
@ -345,7 +343,7 @@ IDBRequest::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
return NS_OK;
}
IDBVersionChangeRequest::~IDBVersionChangeRequest()
IDBOpenDBRequest::~IDBOpenDBRequest()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -355,11 +353,9 @@ IDBVersionChangeRequest::~IDBVersionChangeRequest()
}
// static
already_AddRefed<IDBVersionChangeRequest>
IDBVersionChangeRequest::Create(nsISupports* aSource,
nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwner,
IDBTransaction* aTransaction)
already_AddRefed<IDBOpenDBRequest>
IDBOpenDBRequest::Create(nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwner)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -368,10 +364,8 @@ IDBVersionChangeRequest::Create(nsISupports* aSource,
return nsnull;
}
nsRefPtr<IDBVersionChangeRequest> request(new IDBVersionChangeRequest());
nsRefPtr<IDBOpenDBRequest> request(new IDBOpenDBRequest());
request->mSource = aSource;
request->mTransaction = aTransaction;
request->mScriptContext = aScriptContext;
request->mOwner = aOwner;
@ -379,52 +373,50 @@ IDBVersionChangeRequest::Create(nsISupports* aSource,
}
void
IDBVersionChangeRequest::RootResultVal()
IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
{
mTransaction = aTransaction;
}
void
IDBOpenDBRequest::RootResultVal()
{
NS_ASSERTION(!mResultValRooted, "This should be false!");
NS_HOLD_JS_OBJECTS(this, IDBVersionChangeRequest);
NS_HOLD_JS_OBJECTS(this, IDBOpenDBRequest);
mResultValRooted = true;
}
void
IDBVersionChangeRequest::UnrootResultVal()
IDBOpenDBRequest::UnrootResultVal()
{
NS_ASSERTION(mResultValRooted, "This should be true!");
NS_DROP_JS_OBJECTS(this, IDBVersionChangeRequest);
NS_DROP_JS_OBJECTS(this, IDBOpenDBRequest);
mResultValRooted = false;
}
NS_IMETHODIMP
IDBVersionChangeRequest::SetOnblocked(nsIDOMEventListener* aBlockedListener)
{
return RemoveAddEventListener(NS_LITERAL_STRING(BLOCKED_EVT_STR),
mOnBlockedListener, aBlockedListener);
}
NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, blocked)
NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, upgradeneeded)
NS_IMETHODIMP
IDBVersionChangeRequest::GetOnblocked(nsIDOMEventListener** aBlockedListener)
{
return GetInnerEventListener(mOnBlockedListener, aBlockedListener);
}
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBVersionChangeRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBVersionChangeRequest,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest,
IDBRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnBlockedListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnupgradeneededListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnblockedListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBVersionChangeRequest,
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest,
IDBRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnBlockedListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnupgradeneededListener)
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_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest)
NS_INTERFACE_MAP_ENTRY(nsIIDBOpenDBRequest)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBOpenDBRequest)
NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
NS_IMPL_ADDREF_INHERITED(IDBVersionChangeRequest, IDBRequest)
NS_IMPL_RELEASE_INHERITED(IDBVersionChangeRequest, IDBRequest)
NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
DOMCI_DATA(IDBVersionChangeRequest, IDBVersionChangeRequest)
DOMCI_DATA(IDBOpenDBRequest, IDBOpenDBRequest)

View File

@ -44,9 +44,9 @@
#include "mozilla/dom/indexedDB/IndexedDatabase.h"
#include "nsIIDBRequest.h"
#include "nsIIDBVersionChangeRequest.h"
#include "nsIIDBOpenDBRequest.h"
#include "nsDOMEventTargetHelper.h"
#include "nsDOMEventTargetWrapperCache.h"
#include "nsCycleCollectionParticipant.h"
class nsIScriptContext;
@ -54,7 +54,7 @@ class nsPIDOMWindow;
BEGIN_INDEXEDDB_NAMESPACE
class AsyncConnectionHelper;
class HelperBase;
class IDBTransaction;
class IDBRequest : public nsDOMEventTargetHelper,
@ -82,7 +82,15 @@ public:
void Reset();
nsresult SetDone(AsyncConnectionHelper* aHelper);
nsresult NotifyHelperCompleted(HelperBase* aHelper);
void SetError(nsresult rv)
{
NS_ASSERTION(NS_FAILED(rv), "Er, what?");
NS_ASSERTION(mErrorCode == NS_OK, "Already have an error?");
mErrorCode = rv;
}
nsIScriptContext* ScriptContext()
{
@ -116,30 +124,31 @@ protected:
bool mHaveResultOrErrorCode;
};
class IDBVersionChangeRequest : public IDBRequest,
public nsIIDBVersionChangeRequest
class IDBOpenDBRequest : public IDBRequest,
public nsIIDBOpenDBRequest
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIIDBREQUEST(IDBRequest::)
NS_DECL_NSIIDBVERSIONCHANGEREQUEST
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBVersionChangeRequest,
NS_DECL_NSIIDBOPENDBREQUEST
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBOpenDBRequest,
IDBRequest)
~IDBVersionChangeRequest();
static
already_AddRefed<IDBVersionChangeRequest>
Create(nsISupports* aSource,
nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwner,
IDBTransaction* aTransaction);
already_AddRefed<IDBOpenDBRequest>
Create(nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwner);
void SetTransaction(IDBTransaction* aTransaction);
virtual void RootResultVal();
virtual void UnrootResultVal();
protected:
nsRefPtr<nsDOMEventListenerWrapper> mOnBlockedListener;
~IDBOpenDBRequest();
nsRefPtr<nsDOMEventListenerWrapper> mOnblockedListener;
nsRefPtr<nsDOMEventListenerWrapper> mOnupgradeneededListener;
};
END_INDEXEDDB_NAMESPACE

View File

@ -182,6 +182,14 @@ IDBTransaction::OnRequestFinished()
}
}
void
IDBTransaction::SetTransactionListener(IDBTransactionListener* aListener)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!mListener, "Shouldn't already have a listener!");
mListener = aListener;
}
nsresult
IDBTransaction::CommitOrRollback()
{
@ -190,7 +198,7 @@ IDBTransaction::CommitOrRollback()
TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
NS_ENSURE_STATE(pool);
nsRefPtr<CommitHelper> helper(new CommitHelper(this));
nsRefPtr<CommitHelper> helper(new CommitHelper(this, mListener));
mCachedStatements.Enumerate(DoomCachedStatements, helper);
NS_ASSERTION(!mCachedStatements.Count(), "Statements left!");
@ -775,8 +783,13 @@ IDBTransaction::Abort()
mAborted = true;
mReadyState = nsIIDBTransaction::DONE;
if (Mode() == nsIIDBTransaction::VERSION_CHANGE) {
// If a version change transaction is aborted, the db must be closed
mDatabase->Close();
}
// Fire the abort event if there are no outstanding requests. Otherwise the
// abort event will be fired when all outdtanding requests finish.
// abort event will be fired when all outstanding requests finish.
if (needToCommitOrRollback) {
return CommitOrRollback();
}
@ -908,8 +921,10 @@ IDBTransaction::AfterProcessNextEvent(nsIThreadInternal* aThread,
return NS_OK;
}
CommitHelper::CommitHelper(IDBTransaction* aTransaction)
CommitHelper::CommitHelper(IDBTransaction* aTransaction,
IDBTransactionListener* aListener)
: mTransaction(aTransaction),
mListener(aListener),
mAborted(!!aTransaction->mAborted),
mHaveMetadata(false)
{
@ -965,7 +980,14 @@ CommitHelper::Run()
#ifdef DEBUG
mTransaction->mFiredCompleteOrAbort = true;
#endif
// Tell the listener (if we have one) that we're done
if (mListener) {
mListener->NotifyTransactionComplete(mTransaction);
}
mTransaction = nsnull;
return NS_OK;
}
@ -994,7 +1016,7 @@ CommitHelper::Run()
nsresult rv =
IDBFactory::LoadDatabaseInformation(mConnection,
mTransaction->Database()->Id(),
mOldVersion, mOldObjectStores);
&mOldVersion, mOldObjectStores);
if (NS_SUCCEEDED(rv)) {
mHaveMetadata = true;
}

View File

@ -65,6 +65,15 @@ class CommitHelper;
struct ObjectStoreInfo;
class TransactionThreadPool;
class IDBTransactionListener
{
public:
NS_IMETHOD_(nsrefcnt) AddRef() = 0;
NS_IMETHOD_(nsrefcnt) Release() = 0;
virtual nsresult NotifyTransactionComplete(IDBTransaction* aTransaction) = 0;
};
class IDBTransaction : public nsDOMEventTargetHelper,
public nsIIDBTransaction,
public nsIThreadObserver
@ -95,6 +104,8 @@ public:
void OnNewRequest();
void OnRequestFinished();
void SetTransactionListener(IDBTransactionListener* aListener);
bool StartSavepoint();
nsresult ReleaseSavepoint();
void RollbackSavepoint();
@ -189,6 +200,8 @@ private:
nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
mCachedStatements;
nsRefPtr<IDBTransactionListener> mListener;
// Only touched on the database thread.
nsCOMPtr<mozIStorageConnection> mConnection;
@ -211,7 +224,8 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
CommitHelper(IDBTransaction* aTransaction);
CommitHelper(IDBTransaction* aTransaction,
IDBTransactionListener* aListener);
~CommitHelper();
template<class T>
@ -229,10 +243,11 @@ public:
private:
nsRefPtr<IDBTransaction> mTransaction;
nsRefPtr<IDBTransactionListener> mListener;
nsCOMPtr<mozIStorageConnection> mConnection;
nsAutoTArray<nsCOMPtr<nsISupports>, 10> mDoomedObjects;
nsString mOldVersion;
PRUint64 mOldVersion;
nsTArray<nsAutoPtr<ObjectStoreInfo> > mOldObjectStores;
bool mAborted;

View File

@ -51,6 +51,8 @@
#include "nsStringGlue.h"
#include "nsTArray.h"
#define DB_SCHEMA_VERSION 5
#define BEGIN_INDEXEDDB_NAMESPACE \
namespace mozilla { namespace dom { namespace indexedDB {

View File

@ -149,14 +149,20 @@ class DelayedSetVersion : public nsRunnable
{
public:
DelayedSetVersion(IDBDatabase* aDatabase,
IDBVersionChangeRequest* aRequest,
const nsAString& aVersion,
IDBOpenDBRequest* aRequest,
PRInt64 aOldVersion,
PRInt64 aNewVersion,
AsyncConnectionHelper* aHelper)
: mDatabase(aDatabase),
mRequest(aRequest),
mVersion(aVersion),
mOldVersion(aOldVersion),
mNewVersion(aNewVersion),
mHelper(aHelper)
{ }
{
NS_ASSERTION(aDatabase, "Null database!");
NS_ASSERTION(aRequest, "Null request!");
NS_ASSERTION(aHelper, "Null helper!");
}
NS_IMETHOD Run()
{
@ -165,7 +171,8 @@ public:
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
nsresult rv = mgr->SetDatabaseVersion(mDatabase, mRequest, mVersion,
nsresult rv = mgr->SetDatabaseVersion(mDatabase, mRequest,
mOldVersion, mNewVersion,
mHelper);
NS_ENSURE_SUCCESS(rv, rv);
@ -174,8 +181,9 @@ public:
private:
nsRefPtr<IDBDatabase> mDatabase;
nsRefPtr<IDBVersionChangeRequest> mRequest;
nsString mVersion;
nsRefPtr<IDBOpenDBRequest> mRequest;
PRInt64 mOldVersion;
PRInt64 mNewVersion;
nsRefPtr<AsyncConnectionHelper> mHelper;
};
@ -187,12 +195,14 @@ class VersionChangeEventsRunnable : public nsRunnable
public:
VersionChangeEventsRunnable(
IDBDatabase* aRequestingDatabase,
IDBVersionChangeRequest* aRequest,
IDBOpenDBRequest* aRequest,
nsTArray<nsRefPtr<IDBDatabase> >& aWaitingDatabases,
const nsAString& aVersion)
PRInt64 aOldVersion,
PRInt64 aNewVersion)
: mRequestingDatabase(aRequestingDatabase),
mRequest(aRequest),
mVersion(aVersion)
mOldVersion(aOldVersion),
mNewVersion(aNewVersion)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aRequestingDatabase, "Null pointer!");
@ -230,7 +240,8 @@ public:
}
// Otherwise fire a versionchange event.
nsCOMPtr<nsIDOMEvent> event(IDBVersionChangeEvent::Create(mVersion));
nsRefPtr<nsDOMEvent> event =
IDBVersionChangeEvent::Create(mOldVersion, mNewVersion);
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
bool dummy;
@ -241,8 +252,8 @@ public:
// then fire the blocked event.
for (PRUint32 index = 0; index < mWaitingDatabases.Length(); index++) {
if (!mWaitingDatabases[index]->IsClosed()) {
nsCOMPtr<nsIDOMEvent> event =
IDBVersionChangeEvent::CreateBlocked(mVersion);
nsRefPtr<nsDOMEvent> event =
IDBVersionChangeEvent::CreateBlocked(mOldVersion, mNewVersion);
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
bool dummy;
@ -257,9 +268,10 @@ public:
private:
nsRefPtr<IDBDatabase> mRequestingDatabase;
nsRefPtr<IDBVersionChangeRequest> mRequest;
nsRefPtr<IDBOpenDBRequest> mRequest;
nsTArray<nsRefPtr<IDBDatabase> > mWaitingDatabases;
nsString mVersion;
PRInt64 mOldVersion;
PRInt64 mNewVersion;
};
} // anonymous namespace
@ -512,8 +524,9 @@ IndexedDatabaseManager::IsShuttingDown()
nsresult
IndexedDatabaseManager::SetDatabaseVersion(IDBDatabase* aDatabase,
IDBVersionChangeRequest* aRequest,
const nsAString& aVersion,
IDBOpenDBRequest* aRequest,
PRInt64 aOldVersion,
PRInt64 aNewVersion,
AsyncConnectionHelper* aHelper)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -530,7 +543,8 @@ IndexedDatabaseManager::SetDatabaseVersion(IDBDatabase* aDatabase,
// Same database, just queue this call to run after the current
// SetVersion transaction completes.
nsRefPtr<DelayedSetVersion> delayed =
new DelayedSetVersion(aDatabase, aRequest, aVersion, aHelper);
new DelayedSetVersion(aDatabase, aRequest, aOldVersion, aNewVersion,
aHelper);
if (!runnable->mDelayedRunnables.AppendElement(delayed)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
@ -600,7 +614,7 @@ IndexedDatabaseManager::SetDatabaseVersion(IDBDatabase* aDatabase,
nsRefPtr<VersionChangeEventsRunnable> eventsRunnable =
new VersionChangeEventsRunnable(aDatabase, aRequest, waitingDatabases,
aVersion);
aOldVersion, aNewVersion);
rv = NS_DispatchToCurrentThread(eventsRunnable);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -97,8 +97,9 @@ public:
// Begins the process of setting a database version.
nsresult SetDatabaseVersion(IDBDatabase* aDatabase,
IDBVersionChangeRequest* aRequest,
const nsAString& aVersion,
IDBOpenDBRequest* aRequest,
PRInt64 aOldVersion,
PRInt64 aNewVersion,
AsyncConnectionHelper* aHelper);
// Called when a window is being purged from the bfcache or the user leaves

View File

@ -67,6 +67,7 @@ CPPSRCS = \
IDBFactory.cpp \
IndexedDatabaseManager.cpp \
LazyIdleThread.cpp \
OpenDatabaseHelper.cpp \
TransactionThreadPool.cpp \
$(NULL)
@ -110,7 +111,7 @@ XPIDLSRCS = \
nsIIDBRequest.idl \
nsIIDBTransaction.idl \
nsIIDBVersionChangeEvent.idl \
nsIIDBVersionChangeRequest.idl \
nsIIDBOpenDBRequest.idl \
nsIIndexedDatabaseManager.idl \
$(NULL)

View File

@ -0,0 +1,981 @@
/* ***** 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>
* Kyle Huey <me@kylehuey.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 "OpenDatabaseHelper.h"
#include "IDBEvents.h"
#include "IDBFactory.h"
#include "IndexedDatabaseManager.h"
#include "mozilla/storage.h"
#include "nsIFile.h"
#include "nsContentUtils.h"
#include "nsEscape.h"
#include "nsThreadUtils.h"
USING_INDEXEDDB_NAMESPACE
const extern PRUint32 kDefaultDatabaseTimeoutSeconds = 30;
namespace {
nsresult
GetDatabaseFile(const nsACString& aASCIIOrigin,
const nsAString& aName,
nsIFile** aDatabaseFile)
{
NS_ASSERTION(!aASCIIOrigin.IsEmpty() && !aName.IsEmpty(), "Bad arguments!");
nsCOMPtr<nsIFile> dbFile;
nsresult rv = IDBFactory::GetDirectory(getter_AddRefs(dbFile));
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin);
originSanitized.ReplaceChar(":/", '+');
rv = dbFile->Append(originSanitized);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString filename;
filename.AppendInt(HashString(aName));
nsCString escapedName;
if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) {
NS_WARNING("Can't escape database name!");
return NS_ERROR_UNEXPECTED;
}
const char* forwardIter = escapedName.BeginReading();
const char* backwardIter = escapedName.EndReading() - 1;
nsCString substring;
while (forwardIter <= backwardIter && substring.Length() < 21) {
if (substring.Length() % 2) {
substring.Append(*backwardIter--);
}
else {
substring.Append(*forwardIter++);
}
}
filename.Append(NS_ConvertASCIItoUTF16(substring));
filename.AppendLiteral(".sqlite");
rv = dbFile->Append(filename);
NS_ENSURE_SUCCESS(rv, rv);
dbFile.forget(aDatabaseFile);
return NS_OK;
}
nsresult
CreateTables(mozIStorageConnection* aDBConn)
{
NS_PRECONDITION(!NS_IsMainThread(),
"Creating tables on the main thread!");
NS_PRECONDITION(aDBConn, "Passing a null database connection!");
// Table `database`
nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE database ("
"name TEXT NOT NULL, "
"version INTEGER NOT NULL DEFAULT 0, "
"dataVersion INTEGER NOT NULL"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `object_store`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_store ("
"id INTEGER, "
"name TEXT NOT NULL, "
"key_path TEXT NOT NULL, "
"auto_increment INTEGER NOT NULL DEFAULT 0, "
"PRIMARY KEY (id), "
"UNIQUE (name)"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `object_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_data ("
"id INTEGER, "
"object_store_id INTEGER NOT NULL, "
"data BLOB NOT NULL, "
"key_value DEFAULT NULL, " // NONE affinity
"PRIMARY KEY (id), "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE UNIQUE INDEX key_index "
"ON object_data (key_value, object_store_id);"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `ai_object_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE ai_object_data ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"object_store_id INTEGER NOT NULL, "
"data BLOB NOT NULL, "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE UNIQUE INDEX ai_key_index "
"ON ai_object_data (id, object_store_id);"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `index`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_store_index ("
"id INTEGER, "
"object_store_id INTEGER NOT NULL, "
"name TEXT NOT NULL, "
"key_path TEXT NOT NULL, "
"unique_index INTEGER NOT NULL, "
"object_store_autoincrement INTERGER NOT NULL, "
"PRIMARY KEY (id), "
"UNIQUE (object_store_id, name), "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE index_data ("
"id INTEGER, "
"index_id INTEGER NOT NULL, "
"object_data_id INTEGER NOT NULL, "
"object_data_key NOT NULL, " // NONE affinity
"value NOT NULL, "
"PRIMARY KEY (id), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE, "
"FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX value_index "
"ON index_data (index_id, value);"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `unique_index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE unique_index_data ("
"id INTEGER, "
"index_id INTEGER NOT NULL, "
"object_data_id INTEGER NOT NULL, "
"object_data_key NOT NULL, " // NONE affinity
"value NOT NULL, "
"PRIMARY KEY (id), "
"UNIQUE (index_id, value), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE "
"FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `ai_index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE ai_index_data ("
"id INTEGER, "
"index_id INTEGER NOT NULL, "
"ai_object_data_id INTEGER NOT NULL, "
"value NOT NULL, "
"PRIMARY KEY (id), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE, "
"FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX ai_value_index "
"ON ai_index_data (index_id, value);"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `ai_unique_index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE ai_unique_index_data ("
"id INTEGER, "
"index_id INTEGER NOT NULL, "
"ai_object_data_id INTEGER NOT NULL, "
"value NOT NULL, "
"PRIMARY KEY (id), "
"UNIQUE (index_id, value), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE, "
"FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->SetSchemaVersion(DB_SCHEMA_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
CreateMetaData(mozIStorageConnection* aConnection,
const nsAString& aName)
{
NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
NS_PRECONDITION(aConnection, "Null database!");
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"INSERT OR REPLACE INTO database (name, dataVersion) "
"VALUES (:name, :dataVersion)"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("dataVersion"),
JS_STRUCTURED_CLONE_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
return stmt->Execute();
}
nsresult
UpgradeSchemaFrom4To5(mozIStorageConnection* aConnection)
{
nsresult rv;
mozStorageTransaction transaction(aConnection, false,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
// All we changed is the type of the version column, so lets try to
// convert that to an integer, and if we fail, set it to 0.
nsCOMPtr<mozIStorageStatement> stmt;
rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT name, version, dataVersion "
"FROM database"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
nsString name;
PRInt32 intVersion;
PRInt64 dataVersion;
{
mozStorageStatementScoper scoper(stmt);
bool hasResults;
rv = stmt->ExecuteStep(&hasResults);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(hasResults, NS_ERROR_FAILURE);
nsString version;
rv = stmt->GetString(1, version);
NS_ENSURE_SUCCESS(rv, rv);
intVersion = version.ToInteger(&rv, 10);
if (NS_FAILED(rv)) {
intVersion = 0;
}
rv = stmt->GetString(0, name);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->GetInt64(2, &dataVersion);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE database"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE database ("
"name TEXT NOT NULL, "
"version INTEGER NOT NULL DEFAULT 0, "
"dataVersion INTEGER NOT NULL"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO database (name, version, dataVersion) "
"VALUES (:name, :version, :dataVersion)"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
{
mozStorageStatementScoper scoper(stmt);
rv = stmt->BindStringParameter(0, name);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32Parameter(1, intVersion);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64Parameter(2, dataVersion);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aConnection->SetSchemaVersion(DB_SCHEMA_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
CreateDatabaseConnection(const nsAString& aName,
nsIFile* aDBFile,
mozIStorageConnection** aConnection)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsCOMPtr<nsIFile> dbDirectory;
nsresult rv = aDBFile->GetParent(getter_AddRefs(dbDirectory));
NS_ENSURE_SUCCESS(rv, rv);
bool exists;
rv = aDBFile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota");
nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
nsCOMPtr<mozIStorageConnection> connection;
rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
getter_AddRefs(connection));
if (rv == NS_ERROR_FILE_CORRUPTED) {
// Nuke the database file. The web services can recreate their data.
rv = aDBFile->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
exists = false;
rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
getter_AddRefs(connection));
}
NS_ENSURE_SUCCESS(rv, rv);
// Check to make sure that the database schema is correct.
PRInt32 schemaVersion;
rv = connection->GetSchemaVersion(&schemaVersion);
NS_ENSURE_SUCCESS(rv, rv);
if (schemaVersion != DB_SCHEMA_VERSION) {
// This logic needs to change next time we change the schema!
PR_STATIC_ASSERT(DB_SCHEMA_VERSION == 5);
if (schemaVersion == 4) {
rv = UpgradeSchemaFrom4To5(connection);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
// Nuke it from orbit, it's the only way to be sure.
if (exists) {
// If the connection is not at the right schema version, nuke it.
rv = aDBFile->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
getter_AddRefs(connection));
NS_ENSURE_SUCCESS(rv, rv);
}
mozStorageTransaction transaction(connection, false,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
rv = CreateTables(connection);
NS_ENSURE_SUCCESS(rv, rv);
rv = CreateMetaData(connection, aName);
NS_ENSURE_SUCCESS(rv, rv);
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
}
}
// Check to make sure that the database schema is correct again.
NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) &&
schemaVersion == DB_SCHEMA_VERSION,
"CreateTables failed!");
// Turn on foreign key constraints.
rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"PRAGMA foreign_keys = ON;"
));
NS_ENSURE_SUCCESS(rv, rv);
connection.forget(aConnection);
return NS_OK;
}
class SetVersionHelper : public AsyncConnectionHelper,
public IDBTransactionListener
{
public:
SetVersionHelper(IDBTransaction* aTransaction,
IDBOpenDBRequest* aRequest,
OpenDatabaseHelper* aHelper,
PRUint64 aRequestedVersion,
PRUint64 aCurrentVersion)
: AsyncConnectionHelper(aTransaction, aRequest),
mOpenRequest(aRequest), mOpenHelper(aHelper),
mRequestedVersion(aRequestedVersion),
mCurrentVersion(aCurrentVersion)
{
mTransaction->SetTransactionListener(this);
}
NS_DECL_ISUPPORTS_INHERITED
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
nsresult GetSuccessResult(JSContext* aCx,
jsval* aVal);
// SetVersionHelper never fires an error event at the request. It hands that
// responsibility back to the OpenDatabaseHelper
void OnError() { }
// Need an upgradeneeded event here.
already_AddRefed<nsDOMEvent> CreateSuccessEvent();
nsresult NotifyTransactionComplete(IDBTransaction* aTransaction);
private:
// In-params
nsRefPtr<OpenDatabaseHelper> mOpenHelper;
nsRefPtr<IDBOpenDBRequest> mOpenRequest;
PRUint64 mRequestedVersion;
PRUint64 mCurrentVersion;
};
} // anonymous namespace
NS_IMPL_THREADSAFE_ISUPPORTS1(OpenDatabaseHelper, nsIRunnable);
nsresult
OpenDatabaseHelper::Dispatch(nsIEventTarget* aTarget)
{
NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
mState = eDBWork;
return aTarget->Dispatch(this, NS_DISPATCH_NORMAL);
}
nsresult
OpenDatabaseHelper::RunImmediately()
{
NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
NS_ASSERTION(NS_FAILED(mResultCode),
"Should only be short-circuiting if we failed!");
NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
mState = eFiringEvents;
return this->Run();
}
nsresult
OpenDatabaseHelper::DoDatabaseWork()
{
#ifdef DEBUG
{
bool correctThread;
NS_ASSERTION(NS_SUCCEEDED(IndexedDatabaseManager::Get()->IOThread()->
IsOnCurrentThread(&correctThread)) &&
correctThread,
"Running on the wrong thread!");
}
#endif
if (IndexedDatabaseManager::IsShuttingDown()) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsCOMPtr<nsIFile> dbFile;
nsresult rv = GetDatabaseFile(mASCIIOrigin, mName, getter_AddRefs(dbFile));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = dbFile->GetPath(mDatabaseFilePath);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsCOMPtr<nsIFile> dbDirectory;
rv = dbFile->GetParent(getter_AddRefs(dbDirectory));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
bool exists;
rv = dbDirectory->Exists(&exists);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (exists) {
bool isDirectory;
rv = dbDirectory->IsDirectory(&isDirectory);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
else {
rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
rv = mgr->EnsureQuotaManagementForDirectory(dbDirectory);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsCOMPtr<mozIStorageConnection> connection;
rv = CreateDatabaseConnection(mName, dbFile, getter_AddRefs(connection));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
// Get the data version.
nsCOMPtr<mozIStorageStatement> stmt;
rv = connection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT dataVersion "
"FROM database"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
bool hasResult;
rv = stmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (!hasResult) {
NS_ERROR("Database has no dataVersion!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
PRInt64 dataVersion;
rv = stmt->GetInt64(0, &dataVersion);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (dataVersion > JS_STRUCTURED_CLONE_VERSION) {
NS_ERROR("Bad data version!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
if (dataVersion < JS_STRUCTURED_CLONE_VERSION) {
// Need to upgrade the database, here, before returning to the main thread.
NS_NOTYETIMPLEMENTED("Implement me!");
}
mDatabaseId = HashString(mDatabaseFilePath);
NS_ASSERTION(mDatabaseId, "HashString gave us 0?!");
rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId, &mCurrentVersion,
mObjectStores);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
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 = NS_MAX(indexInfo.id, mLastIndexId);
}
mLastObjectStoreId = NS_MAX(objectStoreInfo->id, mLastObjectStoreId);
}
// See if we need to do a VERSION_CHANGE transaction
if (mCurrentVersion > mRequestedVersion) {
return NS_ERROR_DOM_INDEXEDDB_VERSION_ERR;
}
mState = mCurrentVersion != mRequestedVersion ?
eSetVersionPending :
eFiringEvents;
return NS_OK;
}
nsresult
OpenDatabaseHelper::StartSetVersion()
{
NS_ASSERTION(mState == eSetVersionPending, "Why are we here?");
// In case we fail, fire error events
mState = eFiringEvents;
nsresult rv = EnsureSuccessResult();
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<nsString> storesToOpen;
nsRefPtr<IDBTransaction> transaction =
IDBTransaction::Create(mDatabase, storesToOpen,
IDBTransaction::VERSION_CHANGE,
kDefaultDatabaseTimeoutSeconds, true);
NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<SetVersionHelper> helper =
new SetVersionHelper(transaction, mOpenDBRequest, this, mRequestedVersion,
mCurrentVersion);
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
rv = mgr->SetDatabaseVersion(mDatabase, mOpenDBRequest, mCurrentVersion,
mRequestedVersion, helper);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
// The SetVersionHelper is responsible for dispatching us back to the
// main thread again and changing the state to eSetVersionCompleted.
mState = eSetVersionPending;
return NS_OK;
}
NS_IMETHODIMP
OpenDatabaseHelper::Run()
{
NS_ASSERTION(mState != eCreated, "Dispatch was not called?!?");
if (NS_IsMainThread()) {
// If we need to queue up a SetVersionHelper, do that here.
if (mState == eSetVersionPending) {
nsresult rv = StartSetVersion();
if (NS_SUCCEEDED(rv)) {
return rv;
}
SetError(rv);
// fall through and run the default error processing
}
// We've done whatever work we need to do on the DB thread, and any
// SetVersion stuff is done by now.
NS_ASSERTION(mState == eFiringEvents ||
mState == eSetVersionCompleted, "Why are we here?");
if (mState == eSetVersionCompleted) {
mState = eFiringEvents;
} else {
// Notify the request that we're done, but only if we didn't just finish
// a SetVersionHelper. In the SetVersionHelper case, that helper tells
// the request that it is done, and we avoid calling NotifyHandlerCompleted
// twice.
nsresult rv = mOpenDBRequest->NotifyHelperCompleted(this);
if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
mResultCode = rv;
}
}
NS_ASSERTION(mState == eFiringEvents, "Why are we here?");
if (NS_FAILED(mResultCode)) {
DispatchErrorEvent();
} else {
DispatchSuccessEvent();
}
return NS_OK;
}
// If we're on the DB thread, do that
NS_ASSERTION(mState == eDBWork, "Why are we here?");
mResultCode = DoDatabaseWork();
NS_ASSERTION(mState != eDBWork, "We should be doing something else now.");
return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
}
nsresult
OpenDatabaseHelper::EnsureSuccessResult()
{
DatabaseInfo* dbInfo;
if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
NS_ASSERTION(dbInfo->referenceCount, "Bad reference count!");
++dbInfo->referenceCount;
#ifdef DEBUG
{
NS_ASSERTION(dbInfo->name == mName &&
dbInfo->version == mCurrentVersion &&
dbInfo->id == mDatabaseId &&
dbInfo->filePath == mDatabaseFilePath,
"Metadata mismatch!");
PRUint32 objectStoreCount = mObjectStores.Length();
for (PRUint32 index = 0; index < objectStoreCount; index++) {
nsAutoPtr<ObjectStoreInfo>& info = mObjectStores[index];
NS_ASSERTION(info->databaseId == mDatabaseId, "Huh?!");
ObjectStoreInfo* otherInfo;
NS_ASSERTION(ObjectStoreInfo::Get(mDatabaseId, info->name, &otherInfo),
"ObjectStore not known!");
NS_ASSERTION(info->name == otherInfo->name &&
info->id == otherInfo->id &&
info->keyPath == otherInfo->keyPath &&
info->autoIncrement == otherInfo->autoIncrement &&
info->databaseId == otherInfo->databaseId,
"Metadata mismatch!");
NS_ASSERTION(dbInfo->ContainsStoreName(info->name),
"Object store names out of date!");
NS_ASSERTION(info->indexes.Length() == otherInfo->indexes.Length(),
"Bad index length!");
PRUint32 indexCount = info->indexes.Length();
for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) {
const IndexInfo& indexInfo = info->indexes[indexIndex];
const IndexInfo& otherIndexInfo = otherInfo->indexes[indexIndex];
NS_ASSERTION(indexInfo.id == otherIndexInfo.id,
"Bad index id!");
NS_ASSERTION(indexInfo.name == otherIndexInfo.name,
"Bad index name!");
NS_ASSERTION(indexInfo.keyPath == otherIndexInfo.keyPath,
"Bad index keyPath!");
NS_ASSERTION(indexInfo.unique == otherIndexInfo.unique,
"Bad index unique value!");
NS_ASSERTION(indexInfo.autoIncrement == otherIndexInfo.autoIncrement,
"Bad index autoIncrement value!");
}
}
}
#endif
}
else {
nsAutoPtr<DatabaseInfo> newInfo(new DatabaseInfo());
newInfo->name = mName;
newInfo->id = mDatabaseId;
newInfo->filePath = mDatabaseFilePath;
newInfo->referenceCount = 1;
if (!DatabaseInfo::Put(newInfo)) {
NS_ERROR("Failed to add to hash!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
dbInfo = newInfo.forget();
nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mCurrentVersion,
mObjectStores);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!");
}
dbInfo->nextObjectStoreId = mLastObjectStoreId + 1;
dbInfo->nextIndexId = mLastIndexId + 1;
nsRefPtr<IDBDatabase> database =
IDBDatabase::Create(mOpenDBRequest->ScriptContext(),
mOpenDBRequest->Owner(), dbInfo, mASCIIOrigin);
if (!database) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
NS_ASSERTION(!mDatabase, "Shouldn't have a database yet!");
mDatabase.swap(database);
return NS_OK;
}
nsresult
OpenDatabaseHelper::GetSuccessResult(JSContext* aCx,
jsval* aVal)
{
// Be careful not to load the database twice.
if (!mDatabase) {
nsresult rv = EnsureSuccessResult();
NS_ENSURE_SUCCESS(rv, rv);
}
return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, mDatabase),
aVal);
}
nsresult
OpenDatabaseHelper::NotifySetVersionFinished()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
NS_ASSERTION(mState = eSetVersionPending, "How did we get here?");
mState = eSetVersionCompleted;
// Dispatch ourself back to the main thread
return NS_DispatchToCurrentThread(this);
}
void
OpenDatabaseHelper::DispatchSuccessEvent()
{
NS_ASSERTION(mDatabase, "Doesn't seem very successful to me.");
nsRefPtr<nsDOMEvent> event =
CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR));
if (!event) {
NS_ERROR("Failed to create event!");
return;
}
bool dummy;
mOpenDBRequest->DispatchEvent(event, &dummy);
}
void
OpenDatabaseHelper::DispatchErrorEvent()
{
nsRefPtr<nsDOMEvent> event =
CreateGenericEvent(NS_LITERAL_STRING(ERROR_EVT_STR));
if (!event) {
NS_ERROR("Failed to create event!");
return;
}
PRUint16 errorCode = 0;
DebugOnly<nsresult> rv =
mOpenDBRequest->GetErrorCode(&errorCode);
NS_ASSERTION(NS_SUCCEEDED(rv), "This shouldn't be failing at this point!");
if (!errorCode) {
mOpenDBRequest->SetError(mResultCode);
}
bool dummy;
mOpenDBRequest->DispatchEvent(event, &dummy);
}
NS_IMPL_ISUPPORTS_INHERITED0(SetVersionHelper, AsyncConnectionHelper);
nsresult
SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
NS_ASSERTION(aConnection, "Passing a null connection!");
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE database "
"SET version = :version"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("version"),
mRequestedVersion);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (NS_FAILED(stmt->Execute())) {
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
}
return NS_OK;
}
nsresult
SetVersionHelper::GetSuccessResult(JSContext* aCx,
jsval* aVal)
{
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabase->Id(), &info)) {
NS_ERROR("This should never fail!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
info->version = mRequestedVersion;
NS_ASSERTION(mTransaction, "Better have a transaction!");
mOpenRequest->SetTransaction(mTransaction);
return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, mDatabase),
aVal);
}
already_AddRefed<nsDOMEvent>
SetVersionHelper::CreateSuccessEvent()
{
NS_ASSERTION(mCurrentVersion < mRequestedVersion, "Huh?");
return IDBVersionChangeEvent::CreateUpgradeNeeded(mCurrentVersion,
mRequestedVersion);
}
nsresult
SetVersionHelper::NotifyTransactionComplete(IDBTransaction* aTransaction)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aTransaction, "This is unexpected.");
NS_ASSERTION(mOpenRequest, "Why don't we have a request?");
// If we hit an error, the OpenDatabaseHelper needs to get that error too.
nsresult rv = GetResultCode();
if (NS_FAILED(rv)) {
mOpenHelper->SetError(rv);
}
// If the transaction was aborted, we should throw an error message.
if (aTransaction->IsAborted()) {
mOpenHelper->SetError(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
}
mOpenRequest->SetTransaction(nsnull);
rv = mOpenHelper->NotifySetVersionFinished();
mOpenHelper = nsnull;
return rv;
}

View File

@ -0,0 +1,129 @@
/* ***** 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>
* Kyle Huey <me@kylehuey.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 ***** */
#ifndef mozilla_dom_indexeddb_opendatabasehelper_h__
#define mozilla_dom_indexeddb_opendatabasehelper_h__
#include "AsyncConnectionHelper.h"
#include "DatabaseInfo.h"
#include "IDBDatabase.h"
#include "IDBRequest.h"
#include "nsIRunnable.h"
class mozIStorageConnection;
BEGIN_INDEXEDDB_NAMESPACE
class OpenDatabaseHelper : public HelperBase
{
public:
OpenDatabaseHelper(IDBOpenDBRequest* aRequest,
const nsAString& aName,
const nsACString& aASCIIOrigin,
PRUint64 aRequestedVersion)
: HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
mCurrentVersion(0), mDataVersion(DB_SCHEMA_VERSION), mDatabaseId(0),
mLastObjectStoreId(0), mLastIndexId(0), mState(eCreated),
mResultCode(NS_OK)
{ }
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
nsresult Dispatch(nsIEventTarget* aDatabaseThread);
nsresult RunImmediately();
void SetError(nsresult rv)
{
NS_ASSERTION(NS_FAILED(rv), "Why are you telling me?");
mResultCode = rv;
}
nsresult GetResultCode()
{
return mResultCode;
}
nsresult NotifySetVersionFinished();
protected:
// Methods only called on the main thread
nsresult EnsureSuccessResult();
nsresult StartSetVersion();
nsresult GetSuccessResult(JSContext* aCx,
jsval* aVal);
void DispatchSuccessEvent();
void DispatchErrorEvent();
// Methods only called on the DB thread
nsresult DoDatabaseWork();
private:
// In-params.
nsRefPtr<IDBOpenDBRequest> mOpenDBRequest;
nsString mName;
nsCString mASCIIOrigin;
PRUint64 mRequestedVersion;
// Out-params.
nsTArray<nsAutoPtr<ObjectStoreInfo> > mObjectStores;
PRUint64 mCurrentVersion;
PRUint32 mDataVersion;
nsString mDatabaseFilePath;
PRUint32 mDatabaseId;
PRInt64 mLastObjectStoreId;
PRInt64 mLastIndexId;
nsRefPtr<IDBDatabase> mDatabase;
// State variables
enum OpenDatabaseState {
eCreated = 0, // Not yet dispatched to the DB thread
eDBWork, // Waiting to do/doing work on the DB thread
eFiringEvents, // Waiting to fire/firing events on the main thread
eSetVersionPending, // Waiting on a SetVersionHelper
eSetVersionCompleted, // SetVersionHelper is done
};
OpenDatabaseState mState;
nsresult mResultCode;
};
END_INDEXEDDB_NAMESPACE
#endif // mozilla_dom_indexeddb_opendatabasehelper_h__

View File

@ -51,12 +51,12 @@ interface nsIDOMEventListener;
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBDatabase
* for more information.
*/
[scriptable, uuid(42b38d02-1a29-45f0-99ef-04fd5b441270)]
[scriptable, uuid(ac14faa5-261c-4a84-9616-a700fd606f83)]
interface nsIIDBDatabase : nsISupports
{
readonly attribute DOMString name;
readonly attribute DOMString version;
readonly attribute unsigned long long version;
readonly attribute nsIDOMDOMStringList objectStoreNames;
@ -76,10 +76,6 @@ interface nsIIDBDatabase : nsISupports
void
deleteObjectStore(in AString name);
[implicit_jscontext]
nsIIDBRequest
setVersion(in AString version);
[optional_argc, implicit_jscontext]
nsIIDBTransaction
transaction(in nsIVariant storeNames, // js array of strings

View File

@ -41,7 +41,7 @@
#include "nsISupports.idl"
interface nsIIDBKeyRange;
interface nsIIDBRequest;
interface nsIIDBOpenDBRequest;
interface nsIVariant;
/**
@ -49,10 +49,10 @@ interface nsIVariant;
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
* for more information.
*/
[scriptable, uuid(137d17a5-fac5-4788-87b5-bc3806d7cfaf)]
[scriptable, uuid(4b23254a-ce6d-4442-8c90-9d8744d3c633)]
interface nsIIDBFactory : nsISupports
{
[implicit_jscontext]
nsIIDBRequest
open(in AString name);
nsIIDBOpenDBRequest
open(in AString name, in long long version);
};

View File

@ -43,12 +43,13 @@
interface nsIDOMEventListener;
/**
* IDBReqeust interface. See
* http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBRequest for more
* information.
* IDBOpenDBRequest interface. See
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBOpenDBRequest
* for more information.
*/
[scriptable, uuid(aeaabb0d-594a-4c58-ac5e-68ef3bff927d)]
interface nsIIDBVersionChangeRequest : nsISupports
[scriptable, uuid(91010fbe-1dfb-435d-852e-288d2804c0a7)]
interface nsIIDBOpenDBRequest : nsISupports
{
attribute nsIDOMEventListener onblocked;
attribute nsIDOMEventListener onupgradeneeded;
};

View File

@ -39,8 +39,9 @@
#include "nsIDOMEvent.idl"
[scriptable, uuid(6a232c30-1bc4-4d5b-9ce0-6e7c08934755)]
[scriptable, uuid(2c5159dc-7d71-4fc6-a3b3-884ed7586456)]
interface nsIIDBVersionChangeEvent : nsIDOMEvent
{
readonly attribute AString version;
readonly attribute unsigned long long oldVersion;
readonly attribute unsigned long long newVersion;
};

View File

@ -2,14 +2,14 @@
<html>
<head>
<script>
mozIndexedDB.open(parent.location).onsuccess = function(e) {
var db = e.target.result;
// This should never be called
db.onversionchange = function(e) {
db.transaction(["mystore"]).objectStore("mystore").put({ hello: "fail" }, 42);
}
db.setVersion("1.0").onsuccess = function(e) {
trans = e.target.transaction;
var request = mozIndexedDB.open(parent.location, 1);
request.onupgradeneeded = function(e) {
var db = e.target.result;
// This should never be called
db.onversionchange = function(e) {
db.transaction(["mystore"]).objectStore("mystore").put({ hello: "fail" }, 42);
}
var trans = e.target.transaction;
if (db.objectStoreNames.contains("mystore")) {
db.deleteObjectStore("mystore");
}
@ -19,7 +19,6 @@ mozIndexedDB.open(parent.location).onsuccess = function(e) {
parent.postMessage("go", "http://mochi.test:8888");
}
};
};
</script>
</head>
<body>

View File

@ -2,26 +2,24 @@
<html>
<head>
<script>
var res = {};
mozIndexedDB.open(parent.location).onsuccess = function(e) {
var db = e.target.result;
res.version = db.version;
res.storeCount = db.objectStoreNames.length;
req = db.setVersion("2.0");
req.onblocked = function() {
var res = {};
var request = mozIndexedDB.open(parent.location, 2);
request.onblocked = function() {
res.blockedFired = true;
}
req.onsuccess = function(e) {
var trans = req.transaction;
request.onupgradeneeded = function(e) {
var db = e.target.result;
res.version = db.version;
res.storeCount = db.objectStoreNames.length;
var trans = request.transaction;
trans.objectStore("mystore").get(42).onsuccess = function(e) {
res.value = JSON.stringify(e.target.result);
}
trans.oncomplete = function() {
parent.postMessage(JSON.stringify(res), "http://mochi.test:8888");
}
}
};
};
</script>
</head>

View File

@ -33,7 +33,7 @@ function test1()
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
setFinishedCallback(function(result, exception) {
ok(result == "11", "Set version on database in " + testPageURL1);
ok(result == 11, "Set version on database in " + testPageURL1);
ok(!exception, "No exception");
gBrowser.removeCurrentTab();
@ -51,7 +51,7 @@ function test2()
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
setFinishedCallback(function(result, exception) {
ok(result == "11", "Set version on database in " + testPageURL2);
ok(result == 11, "Set version on database in " + testPageURL2);
ok(!exception, "No exception");
gBrowser.removeCurrentTab();
@ -79,7 +79,7 @@ function test4()
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
setFinishedCallback(function(result, exception) {
ok(result == "11", "Got correct version on database in " + testPageURL3);
ok(result == 11, "Got correct version on database in " + testPageURL3);
ok(!exception, "No exception");
gBrowser.removeCurrentTab();
@ -97,7 +97,9 @@ function test5()
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
setFinishedCallback(function(result, exception) {
ok(result == "", "Got correct version on database in " + testPageURL4);
// XXXkhuey this isn't really testing anything until we get the default
// version behavior implemented ...
ok(result == 11, "Got correct version on database in " + testPageURL4);
ok(!exception, "No exception");
gBrowser.removeCurrentTab();

View File

@ -9,9 +9,9 @@
<script type="text/javascript;version=1.7">
function testSteps()
{
let request = mozIndexedDB.open("browser_forgetThisSite.js");
let request = mozIndexedDB.open("browser_forgetThisSite.js", 11);
request.onerror = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
if (event.type == "error") {
@ -20,17 +20,7 @@
else {
let db = event.target.result;
request = db.setVersion("11");
request.onerror = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
if (event.type == "error") {
testException = event.target.errorCode;
}
else {
testResult = db.version;
}
testResult = db.version;
event.target.transaction.oncomplete = finishTest;
yield;

View File

@ -9,7 +9,7 @@
<script type="text/javascript;version=1.7">
function testSteps()
{
let request = mozIndexedDB.open("browser_forgetThisSite.js");
let request = mozIndexedDB.open("browser_forgetThisSite.js", 11);
request.onerror = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;

View File

@ -12,7 +12,7 @@
const name = window.location.pathname;
const description = "My Test Database";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;

View File

@ -10,6 +10,7 @@
const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
let db;
let version = window.location.href.charAt(window.location.href.length - 1);
function onAddMore() {
let transaction = db.transaction("foo", READ_WRITE);
@ -36,10 +37,11 @@
window.removeEventListener("indexedDB-addMore", onAddMore, true);
window.removeEventListener("indexedDB-done", onDone, true);
let request = db.setVersion("2");
let request = mozIndexedDB.open(window.location.pathname, version++);
request.onerror = errorHandler;
request.onsuccess = function(event) {
request.onupgradeneeded = function(event) {
db.deleteObjectStore("foo");
db.onversionchange = function () { db.close(); };
request.transaction.oncomplete = function(event) {
testResult = "finished";
testException = undefined;
@ -56,17 +58,14 @@
window.addEventListener("indexedDB-addMore", onAddMore, true);
window.addEventListener("indexedDB-done", onDone, true);
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, version++, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db.onversionchange = function () { db.close(); };
db.createObjectStore("foo", { autoIncrement: true });

View File

@ -71,7 +71,7 @@ function test1()
}, true);
info("loading test page: " + testPageURL);
content.location = testPageURL;
content.location = testPageURL + "?v=1";
}
function test2()
@ -136,5 +136,5 @@ function test2()
}, true);
info("loading test page: " + testPageURL);
content.location = testPageURL;
content.location = testPageURL + "?v=3";
}

View File

@ -77,7 +77,7 @@ function test1()
}, true);
info("loading test page: " + testPageURL);
content.location = testPageURL;
content.location = testPageURL + "?v=5";
}
function test2()
@ -145,5 +145,5 @@ function test2()
}, true);
info("loading test page: " + testPageURL);
content.location = testPageURL;
content.location = testPageURL + "?v=7";
}

View File

@ -56,27 +56,20 @@
.add(uri, "indexedDB",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
let request = mozIndexedDB.open(window.location.pathname);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onsuccess = unexpectedSuccessHandler;
request.onerror = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.version, "", "Correct version");
is(db.version, 1, "Correct version");
is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
let request = db.setVersion("1");
request.onsuccess = grabEventAndContinueHandler;
request.onerror = errorHandler;
event = yield;
event.target.transaction.oncomplete = unexpectedSuccessHandler;
event.target.transaction.onabort = grabEventAndContinueHandler;
is(db.version, "1", "Correct version");
is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
let objectStore = db.createObjectStore("foo");
is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
@ -95,13 +88,21 @@
event = yield;
is(event.type, "abort", "Got a transaction abort event");
is(db.version, "", "Correct version");
//todo(db.version, 1, "Correct version");
is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
request = db.setVersion("1");
request.onsuccess = grabEventAndContinueHandler;
request.onerror = errorHandler;
event = yield;
is(event.type, "error", "Got request error event");
is(event.target.errorCode, IDBDatabaseException.ABORT_ERR, "Right error code");
db.close();
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
event.target.transaction.oncomplete = grabEventAndContinueHandler;
event.target.transaction.onabort = unexpectedSuccessHandler;

View File

@ -95,20 +95,15 @@
.add(uri, "indexedDB",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorEventCounter;
db.addEventListener("error", errorEventCounter, true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
event.target.transaction.oncomplete = grabEventAndContinueHandler;
db.createObjectStore("foo", { autoIncrement: true });

View File

@ -59,9 +59,25 @@
.add(uri, "indexedDB",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
let request = mozIndexedDB.open(window.location.pathname);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = grabEventAndContinueHandler;
request.onsuccess = errorHandler;
request.onupgradeneeded = function () {
throw "STOP";
};
let event = yield;
is(event.type, "error",
"Throwing during an upgradeneeded event should fire an error.");
ok(event.target.result instanceof IDBDatabase, "Should have a DB");
event.target.result.close();
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = grabEventAndContinueHandler;
request.onblocked = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let openrequest = request;
let event = yield;
let db = event.target.result;
@ -69,16 +85,10 @@
event.preventDefault();
};
is(db.version, "", "Correct version");
is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
db.setVersion("1").onsuccess = grabEventAndContinueHandler;
event = yield;
event.target.transaction.oncomplete = unexpectedSuccessHandler;
event.target.transaction.onabort = grabEventAndContinueHandler;
is(db.version, "1", "Correct version");
is(db.version, 1, "Correct version");
is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
let objectStore = db.createObjectStore("foo");
@ -95,6 +105,11 @@
is(event.type, "abort", "Got transaction abort event");
event = yield;
is(event.type, "error", "Got IDBOpenDBRequest error event");
is(event.target, openrequest, "Right event target");
finishTest();
yield;
}

View File

@ -4,17 +4,15 @@
<script>
var db;
function startDBWork() {
mozIndexedDB.open(parent.location).onsuccess = function(e) {
mozIndexedDB.open(parent.location, 1).onupgradeneeded = function(e) {
db = e.target.result;
db.setVersion("1.0").onsuccess = function(e) {
var trans = e.target.transaction;
if (db.objectStoreNames.contains("mystore")) {
db.deleteObjectStore("mystore");
}
var store = db.createObjectStore("mystore");
store.add({ hello: "world" }, 42);
trans.oncomplete = madeMod;
};
var trans = e.target.transaction;
if (db.objectStoreNames.contains("mystore")) {
db.deleteObjectStore("mystore");
}
var store = db.createObjectStore("mystore");
store.add({ hello: "world" }, 42);
trans.oncomplete = madeMod;
};
}

View File

@ -15,18 +15,13 @@
const name = window.location.pathname;
const description = "My Test Database";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = request.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
ok(event.target === request, "Good event target");
let objectStore = db.createObjectStore("foo", { keyPath: "" });

View File

@ -12,17 +12,14 @@
<script type="text/javascript;version=1.7">
function testSteps()
{
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = request.result;
db.onerror = errorHandler;
db.setVersion("1").onsuccess = grabEventAndContinueHandler;
let event = yield;
let objectStore = db.createObjectStore("foo", { keyPath: "id",
autoIncrement: true });
objectStore.createIndex("first","first");

View File

@ -15,18 +15,13 @@
const name = window.location.pathname;
const description = "My Test Database";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = request.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore("foo", { keyPath: "keyPath" });
request = objectStore.add({keyPath:"foo"});
@ -36,6 +31,7 @@
try {
request = objectStore.add({});
ok(false, "Shouldn't get here!");
}
catch (e) {
is(e.code, IDBDatabaseException.DATA_ERR, "Good error");

View File

@ -55,7 +55,7 @@
iframe.src = "bfcache_iframe2.html";
res = JSON.parse((yield).data);
is(res.version, "1.0", "version was set correctly");
is(res.version, 2, "version was set correctly");
is(res.storeCount, 1, "correct set of stores");
ok(!("blockedFired" in res), "blocked shouldn't fire");
is(res.value, JSON.stringify({ hello: "world" }),

View File

@ -18,18 +18,13 @@
const description = "My Test Database";
const entryCount = 1000;
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = request.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
event.target.transaction.oncomplete = continueToNextStep;
let objectStore = db.createObjectStore("foo", { autoIncrement: true });

View File

@ -27,17 +27,12 @@
{ name: "3", keyPath: "value", options: { unique: false } },
];
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.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];
let objectStore = info.hasOwnProperty("options") ?

View File

@ -15,26 +15,29 @@
const data = { id: new Date().getTime(),
num: parseInt(Math.random() * 1000) };
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.setVersion("1").onsuccess = grabEventAndContinueHandler;
event = yield;
event.target.transaction.oncomplete = continueToNextStep;
// Make object store, add data.
let objectStore = db.createObjectStore("foo", { keyPath: "id" });
objectStore.add(data);
yield;
db.close();
db.setVersion("2").onsuccess = grabEventAndContinueHandler;
event = yield;
let request = mozIndexedDB.open(window.location.pathname, 2);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db2 = event.target.result;
db2.onerror = errorHandler;
event.target.transaction.oncomplete = continueToNextStep;
@ -46,8 +49,8 @@
let seenCount = 0;
db.transaction("foo").objectStore("foo").index("foo")
.openKeyCursor().onsuccess = function(event) {
db2.transaction("foo").objectStore("foo").index("foo")
.openKeyCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
is(cursor.key, data.num, "Good key");

View File

@ -31,25 +31,16 @@
{ name: "11", options: { keyPath: "foo", autoIncrement: true } }
];
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
ok(event.target.source === mozIndexedDB,
"event.target.source is correct");
let db = event.target.result;
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.target.source === db, "event.target.source is correct");
try {
db.createObjectStore(null);
ok(false, "createObjectStore with null name should throw");

View File

@ -29,16 +29,12 @@
// Post-add and post-remove data ordered by name.
const objectStoreDataNameSort = [ 1, 4, 5, 2, 3 ];
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.setVersion("1").onsuccess = grabEventAndContinueHandler;
event = yield;
event.target.transaction.oncomplete = continueToNextStep;
let objectStore = db.createObjectStore("foo", { keyPath: "ss" });

View File

@ -30,23 +30,18 @@
entry: { data: START_DATA } },
];
let request = mozIndexedDB.open(name, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
for (let i = 0; i < objectStoreInfo.length; i++) {
// Create our object stores.
let info = objectStoreInfo[i];
ok(true, "1");
request = db.setVersion("1");
request = mozIndexedDB.open(name, i + 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
event = yield;
let db = event.target.result;
ok(true, "2");
let objectStore = info.hasOwnProperty("options") ?
db.createObjectStore(info.name, info.options) :
@ -99,6 +94,7 @@
ok(true, "7");
SimpleTest.ok(obj.data, event.target.result.data,
"Unique index was properly updated.");
db.close();
}
finishTest();

View File

@ -19,18 +19,13 @@
is(keys.length, sortedKeys.length, "Good key setup");
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let objectStore = db.createObjectStore("autoIncrement",
{ autoIncrement: true });

View File

@ -16,22 +16,14 @@
const description = "My Test Database";
const objectStoreName = "Objects";
var request = mozIndexedDB.open(name, description);
var request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
var event = yield;
ok(event.target.source === mozIndexedDB, "correct event.target.source");
is(event.target.source, null, "correct event.target.source");
var db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(event.target.source === db, "correct event.target.source");
var objectStore = db.createObjectStore(objectStoreName,
{ autoIncrement: true });
request = objectStore.add({});

View File

@ -17,18 +17,13 @@
const values = [ "a", "1", 1, "foo", 300, true, false, 4.5, null ];
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore("foo", { autoIncrement: true });
request = objectStore.getAll();

View File

@ -17,18 +17,13 @@
const objectStore = { name: "Objects",
options: { keyPath: "id", autoIncrement: true } };
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db1 = event.target.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.options);
@ -36,7 +31,7 @@
continueToNextStep();
yield;
request = mozIndexedDB.open(name, description);
request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;

View File

@ -57,18 +57,13 @@
{ key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
];
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore(objectStoreName);
// First, add all our data to the object store.

View File

@ -57,18 +57,13 @@
{ key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
];
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore(objectStoreName, {});
// First, add all our data to the object store.

View File

@ -29,18 +29,15 @@
{ ss: "237-23-7733", name: "Bob", height: 65 }
];
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.setVersion("1").onsuccess = grabEventAndContinueHandler;
event = yield;
event.target.result.oncomplete = continueToNextStep;
event.target.transaction.oncomplete = continueToNextStep;
for (let objectStoreIndex in objectStoreData) {
const objectStoreInfo = objectStoreData[objectStoreIndex];

View File

@ -68,18 +68,13 @@
{ key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
];
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore(objectStoreName, { keyPath: "" });
// First, add all our data to the object store.

View File

@ -48,18 +48,13 @@
{ key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
];
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore(objectStoreName, { } );
let addedData = 0;

View File

@ -15,9 +15,9 @@
const name = window.location.pathname;
const description = "My Test Database";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -25,11 +25,6 @@
event.preventDefault();
}, false);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let objectStore = db.createObjectStore("foo", { autoIncrement: true });
request = objectStore.add({});

View File

@ -30,7 +30,7 @@
is(iframe.contentWindow.location.href, "about:blank",
"should nagivate to about:blank");
let request = mozIndexedDB.open(location);
let request = mozIndexedDB.open(location, 1);
request.onsuccess = grabEventAndContinueHandler;
let event = yield;

View File

@ -25,19 +25,15 @@
{ name: "b", options: { unique: true } }
];
let request = mozIndexedDB.open(name, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
var j = 0;
for (let i in objectStores) {
request = db.setVersion("1");
let request = mozIndexedDB.open(name, ++j, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
let objectStore =
db.createObjectStore(objectStores[i].name,
{ keyPath: "id",
@ -58,12 +54,18 @@
event = yield;
ok(event.target.result == 1 || event.target.result == 2, "Good id");
db.close();
}
SimpleTest.executeSoon(function() { testGenerator.next(); });
yield;
let objectStore = event.target.result;
let request = mozIndexedDB.open(name, j, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
for (let i in objectStores) {
for (let j in indexes) {

View File

@ -18,9 +18,9 @@ function testSteps()
const name = window.location.pathname;
const description = "My Test Database";
var request = mozIndexedDB.open(name, description);
var request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
var event = yield;
var db = event.target.result;
@ -32,11 +32,6 @@ function testSteps()
keyName: "id",
};
let request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore(test.name,
{ keyPath: test.keyName,
autoIncrement: test.autoIncrement });

View File

@ -18,13 +18,6 @@ function testSteps()
const name = window.location.pathname;
const description = "My Test Database";
var request = mozIndexedDB.open(name, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
var event = yield;
var db = event.target.result;
var data = [
{ name: "inline key; key generator",
autoIncrement: true,
@ -55,11 +48,12 @@ function testSteps()
for (let i = 0; i < data.length; i++) {
let test = data[i];
let request = db.setVersion("1");
let request = mozIndexedDB.open(name, i+1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
let objectStore = db.createObjectStore(test.name,
{ keyPath: test.keyName,
@ -92,6 +86,7 @@ function testSteps()
event = yield;
ok(event.target.result === undefined, "Object was deleted");
db.close();
}
finishTest();

View File

@ -12,18 +12,12 @@
<script type="text/javascript;version=1.7">
function testSteps()
{
let request = mozIndexedDB.open(window.location.pathname, "");
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let transaction = event.target.transaction;
let objectStore1 = db.createObjectStore("foo");

View File

@ -14,25 +14,17 @@
{
const data = { key: 5, index: 10 };
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db;
setTimeout(function() {
db = request.result;
continueToNextStep();
}, 0);
yield;
let db = event.target.result;
ok(db instanceof IDBDatabase, "Got a real database");
db.onerror = errorHandler;
db.setVersion("1").onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore("foo", { keyPath: "key",
autoIncrement: true });
let index = objectStore.createIndex("foo", "index");

View File

@ -18,7 +18,7 @@
let request;
try {
request = mozIndexedDB.open("", "");
request = mozIndexedDB.open("", 1);
ok(false, "Open with empty name should have thrown!");
}
catch(e) {
@ -28,7 +28,7 @@
}
try {
request = mozIndexedDB.open(null, "");
request = mozIndexedDB.open(null, 1);
ok(false, "Open with null name should have thrown!");
}
catch(e) {
@ -37,14 +37,14 @@
is(request, undefined, "Shouldn't be set to anything");
}
request = mozIndexedDB.open(name, description);
request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.name, name, "Bad name");
is(db.version, "", "Bad version");
is(db.version, 1, "Bad version");
is(db.objectStoreNames.length, 0, "Bad objectStores list");
is(db.name, request.result.name, "Bad name");

View File

@ -17,21 +17,14 @@
const description = "My Test Database";
const objectStoreName = "Objects";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.objectStoreNames.length, 0, "Bad objectStores list");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(db.objectStoreNames.length, 0, "Bad objectStores list");
let objectStore = db.createObjectStore(objectStoreName,
{ keyPath: "foo" });

View File

@ -18,23 +18,19 @@
const description = "My Test Database";
const objectStores = [ "foo", "bar" ];
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = function(event) {
event.target.transaction.oncomplete = grabEventAndContinueHandler;
for (let i in objectStores) {
db.createObjectStore(objectStores[i], { autoIncrement: true });
}
};
yield;
event.target.transaction.oncomplete = grabEventAndContinueHandler;
for (let i in objectStores) {
db.createObjectStore(objectStores[i], { autoIncrement: true });
}
let event = yield;
is(db.objectStoreNames.length, objectStores.length,
"Correct objectStoreNames list");

View File

@ -19,18 +19,13 @@
let testString = { key: 0, value: "testString" };
let testInt = { key: 1, value: 1002 };
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore(objectStoreName,
{ autoIncrement: 0 });

View File

@ -19,18 +19,13 @@
let testString = { value: "testString" };
let testInt = { value: 1002 };
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore(objectStoreName,
{ autoIncrement: 1 });

View File

@ -19,19 +19,14 @@
const description = "My Test Database";
const osName = "foo";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db.createObjectStore(osName, { autoIncrement: "true" });
let key1, key2;

View File

@ -18,19 +18,14 @@
const description = "My Test Database";
const indexName = "My Test Index";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore("test store", { keyPath: "foo" });
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
is(db.objectStoreNames.item(0), objectStore.name, "Correct name");

View File

@ -20,19 +20,14 @@
const description = "My Test Database";
const objectStoreName = "Objects";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore(objectStoreName,
{ keyPath: "foo" });
@ -52,10 +47,14 @@
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
request = db.setVersion("2");
db.close();
let request = mozIndexedDB.open(name, 2, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.deleteObjectStore(objectStore.name);
is(db.objectStoreNames.length, 0, "Correct objectStores list");
@ -78,10 +77,14 @@
continueToNextStep();
yield;
request = db.setVersion("3");
db.close();
let request = mozIndexedDB.open(name, 3, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
objectStore = db.createObjectStore(objectStoreName, { keyPath: "foo" });

View File

@ -18,26 +18,17 @@
const LOADING = Components.interfaces.nsIIDBRequest.LOADING;
const DONE = Components.interfaces.nsIIDBRequest.DONE;
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
is(request.readyState, LOADING, "Correct readyState");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
is(request.readyState, DONE, "Correct readyState");
let db = event.target.result;
request = db.setVersion("1");
is(request.readyState, LOADING, "Correct readyState");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
is(request.readyState, DONE, "Correct readyState");
let objectStore = db.createObjectStore("foo");
let key = 10;

View File

@ -19,7 +19,7 @@ function testSteps()
const name = window.location.pathname;
const description = "My Test Database";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
@ -27,26 +27,31 @@ function testSteps()
let db = event.target.result;
// Check default state.
is(db.version, "", "Correct default version for a new database.");
is(db.version, 1, "Correct default version for a new database.");
const versions = [
"1.0",
"",
7,
42,
];
db.close();
for (let i = 0; i < versions.length; i++) {
let version = versions[i];
request = db.setVersion(version);
let request = mozIndexedDB.open(name, version, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.version, version, "Database version number updated correctly");
is(event.target.transaction.mode, VERSION_CHANGE, "Correct mode");
SimpleTest.executeSoon(function() { testGenerator.next(); });
yield;
db.close();
}
finishTest();

View File

@ -19,34 +19,37 @@ function testSteps()
const name = window.location.pathname;
const description = "My Test Database";
let request = mozIndexedDB.open(name, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let request = mozIndexedDB.open(name, 1, description);
request.onerror = grabEventAndContinueHandler;
request.onsuccess = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.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.version, 1, "Correct version");
is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
is(objectStore.indexNames.length, 1, "Correct indexNames length");
event.target.transaction.oncomplete = unexpectedSuccessHandler;
event.target.transaction.onabort = grabEventAndContinueHandler;
event.target.transaction.abort();
let transaction = event.target.transaction;
transaction.oncomplete = unexpectedSuccessHandler;
transaction.onabort = grabEventAndContinueHandler;
transaction.abort();
event = yield;
is(event.type, "abort", "Got transaction abort event");
is(event.target, transaction, "Right target");
is(db.version, "", "Correct version");
todo(db.version, 1, "Correct version");
is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
event = yield;
is(event.type, "error", "Got request error event");
is(event.target, request, "Right target");
finishTest();
yield;
}

View File

@ -15,7 +15,21 @@
const name = window.location.pathname;
const description = "My Test Database";
let request = mozIndexedDB.open(name, description);
// Open a datbase for the first time.
let request = mozIndexedDB.open(name, 1, description);
// Sanity checks
ok(request instanceof IDBRequest, "Request should be an IDBRequest");
ok(request instanceof IDBOpenDBRequest, "Request should be an IDBOpenDBRequest");
ok(request instanceof EventTarget, "Request should be an EventTarget");
is(request.source, null, "Request should have no source");
try {
request.result;
ok(false, "Getter should have thrown!");
} catch (e if e.result == 0x80660006 /* NS_ERROR_DOM_INDEXEDDB_NOTALLOWED_ERR */) {
ok(true, "Getter threw the right exception");
}
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
@ -26,65 +40,111 @@
db1 = event.target.result;
db1.addEventListener("versionchange", function(event) {
ok(true, "Got version change event");
ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
is(event.target.source, null, "Correct source");
is(event.target, db1, "Correct target");
is(event.target.version, "", "Correct db version");
is(event.version, "1", "Correct event version");
is(event.target.version, 1, "Correct db version");
is(event.oldVersion, 1, "Correct event oldVersion");
is(event.newVersion, 2, "Correct event newVersion");
is(versionChangeEventCount++, 0, "Correct count");
db1.close();
}, false);
request = mozIndexedDB.open(name, description);
// Open the database again and trigger an upgrade that should succeed
request = mozIndexedDB.open(name, 2, description);
request.onerror = errorHandler;
request.onsuccess = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onblocked = errorHandler;
event = yield;
// Test the upgradeneeded event.
ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
ok(event.target.result instanceof IDBDatabase, "Good result");
db2 = event.target.result;
is(event.target.transaction.mode, IDBTransaction.VERSION_CHANGE,
"Correct mode");
is(db2.version, 2, "Correct db version");
is(event.oldVersion, 1, "Correct event oldVersion");
is(event.newVersion, 2, "Correct event newVersion");
request.onupgradeneeded = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db2 = event.target.result;
db2.addEventListener("versionchange", function(event) {
ok(true, "Got version change event");
ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
is(event.target.source, null, "Correct source");
is(event.target, db2, "Correct target");
is(event.target.version, "1", "Correct db version");
is(event.version, "2", "Correct event version");
is(event.target.version, 2, "Correct db version");
is(event.oldVersion, 2, "Correct event oldVersion");
is(event.newVersion, 3, "Correct event newVersion");
is(versionChangeEventCount++, 1, "Correct count");
}, false);
request = db2.setVersion("1");
// Test opening the existing version again
request = mozIndexedDB.open(name, 2, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onblocked = errorHandler;
event = yield;
ok(event.target.result === event.target.transaction, "Good result");
is(event.target.transaction.mode, IDBTransaction.VERSION_CHANGE,
"Correct mode");
is(db2.version, "1", "Correct db version");
db3 = event.target.result;
request = mozIndexedDB.open(name, description);
// Test an upgrade that should fail
request = mozIndexedDB.open(name, 3, description);
request.onerror = errorHandler;
request.onsuccess = errorHandler;
request.onupgradeneeded = errorHandler;
request.onblocked = grabEventAndContinueHandler;
event = yield;
ok(true, "Got version change blocked event");
ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
is(event.target.source, null, "Correct source");
is(event.target.transaction, null, "Correct transaction");
is(event.target, request, "Correct target");
is(db3.version, 2, "Correct db version");
is(event.oldVersion, 2, "Correct event oldVersion");
is(event.newVersion, 3, "Correct event newVersion");
versionChangeEventCount++;
db2.close();
db3.close();
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
event = yield;
db3 = event.target.result;
db3.close();
request = db3.setVersion("2");
// Test another upgrade that should succeed.
request = mozIndexedDB.open(name, 4);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onblocked = function(event) {
ok(true, "Got version change blocked event");
is(event.target.source, db3, "Correct source");
is(event.target, request, "Correct target");
is(event.target.source.version, "1", "Correct db version");
is(event.version, "2", "Correct event version");
versionChangeEventCount++;
db2.close();
};
request.onsuccess = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onblocked = errorHandler;
event = yield;
ok(event.target.result === event.target.transaction, "Good result");
ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
ok(event.target.result instanceof IDBDatabase, "Good result");
is(event.target.transaction.mode, IDBTransaction.VERSION_CHANGE,
"Correct mode");
is(db3.version, "2", "Correct db version");
is(event.oldVersion, 3, "Correct event oldVersion");
is(event.newVersion, 4, "Correct event newVersion");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(event.target.result instanceof IDBDatabase, "Expect a database here");
is(event.target.result.version, 4, "Right version");
todo_is(db3.version, 3, "After closing the version should not change!");
todo_is(db2.version, 2, "After closing the version should not change!");
todo_is(db1.version, 1, "After closing the version should not change!");
is(versionChangeEventCount, 3, "Saw all expected events");

View File

@ -12,19 +12,14 @@
<script type="text/javascript;version=1.7">
function testSteps()
{
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
let request = db.setVersion("1");
request.onsuccess = grabEventAndContinueHandler;
request.onerror = errorHandler;
event = yield;
event.target.result.oncomplete = continueToNextStep;
event.target.transaction.oncomplete = continueToNextStep;
let objectStore = db.createObjectStore("foo");
objectStore.add({}, 1).onerror = errorHandler;

View File

@ -26,9 +26,9 @@
const description = "My Test Database";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -36,11 +36,6 @@
let transaction;
let objectStore;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
transaction = event.target.transaction;
objectStore = db.createObjectStore("foo", { autoIncrement: true });

View File

@ -12,17 +12,14 @@
<script type="text/javascript;version=1.7">
function testSteps()
{
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.setVersion("1").onsuccess = grabEventAndContinueHandler;
let event = yield;
event.target.transaction.oncomplete = continueToNextStep;
db.createObjectStore("foo", { autoIncrement: true });

View File

@ -12,17 +12,14 @@
<script type="text/javascript;version=1.7">
function testSteps()
{
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.setVersion("1").onsuccess = grabEventAndContinueHandler;
event = yield;
event.target.transaction.oncomplete = continueToNextStep;
db.createObjectStore("foo");
yield;

View File

@ -20,18 +20,13 @@
const name = window.location.pathname;
const description = "My Test Database";
let request = mozIndexedDB.open(name, description);
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
is(event.target.transaction.mode, VERSION_CHANGE, "Correct mode");
let objectStore = db.createObjectStore("foo", { autoIncrement: true });

View File

@ -15,7 +15,7 @@
function runIndexedDBTest() {
try {
let request = mozIndexedDB.open(window.location.pathname);
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onsuccess = function(event) {
report(!!(event.target.result instanceof IDBDatabase));
}

View File

@ -452,8 +452,8 @@ members = [
'nsIIDBRequest.*',
'nsIIDBTransaction.*',
'nsIIDBFactory.*',
'nsIIDBOpenDBRequest.*',
'nsIIDBVersionChangeEvent.*',
'nsIIDBVersionChangeRequest.*',
'nsIIndexedDatabaseUsageCallback.*',
'nsIIndexedDatabaseManager.*',
]

View File

@ -663,7 +663,7 @@ resultConvTemplates = {
" return xpc_qsInt32ToJsval(cx, result, ${jsvalPtr});\n",
'long long':
" return xpc_qsInt64ToJsval(cx, result, ${jsvalPtr};\n",
" return xpc_qsInt64ToJsval(cx, result, ${jsvalPtr});\n",
'unsigned short':
" ${jsvalRef} = INT_TO_JSVAL((int32) result);\n"