From 81bc750723a18f21cd17d1b173cd2a4dda9cea6e Mon Sep 17 00:00:00 2001 From: Ben Murdoch Date: Tue, 24 May 2011 11:24:40 +0100 Subject: Merge WebKit at r80534: Intial merge by Git Change-Id: Ia7a83357124c9e1cdb1debf55d9661ec0bd09a61 --- Source/WebCore/storage/Database.cpp | 8 +- Source/WebCore/storage/IDBAbortEvent.cpp | 55 -- Source/WebCore/storage/IDBAbortEvent.h | 57 -- Source/WebCore/storage/IDBAny.cpp | 16 +- Source/WebCore/storage/IDBAny.h | 5 + Source/WebCore/storage/IDBBackingStore.cpp | 996 +++++++++++++++++++++ Source/WebCore/storage/IDBBackingStore.h | 114 +++ Source/WebCore/storage/IDBCallbacks.h | 2 +- Source/WebCore/storage/IDBCompleteEvent.cpp | 55 -- Source/WebCore/storage/IDBCompleteEvent.h | 57 -- Source/WebCore/storage/IDBCursor.cpp | 29 +- Source/WebCore/storage/IDBCursor.h | 20 +- Source/WebCore/storage/IDBCursor.idl | 3 +- Source/WebCore/storage/IDBCursorBackendImpl.cpp | 101 +-- Source/WebCore/storage/IDBCursorBackendImpl.h | 39 +- Source/WebCore/storage/IDBCursorBackendInterface.h | 10 +- Source/WebCore/storage/IDBCursorWithValue.cpp | 52 ++ Source/WebCore/storage/IDBCursorWithValue.h | 51 ++ Source/WebCore/storage/IDBCursorWithValue.idl | 33 + Source/WebCore/storage/IDBDatabase.cpp | 57 +- Source/WebCore/storage/IDBDatabase.h | 27 +- Source/WebCore/storage/IDBDatabase.idl | 5 +- Source/WebCore/storage/IDBDatabaseBackendImpl.cpp | 179 ++-- Source/WebCore/storage/IDBDatabaseBackendImpl.h | 26 +- .../WebCore/storage/IDBDatabaseBackendInterface.h | 8 +- Source/WebCore/storage/IDBDatabaseCallbacks.h | 47 + Source/WebCore/storage/IDBDatabaseException.h | 4 +- Source/WebCore/storage/IDBDatabaseException.idl | 2 + Source/WebCore/storage/IDBErrorEvent.cpp | 58 -- Source/WebCore/storage/IDBErrorEvent.h | 66 -- Source/WebCore/storage/IDBErrorEvent.idl | 37 - Source/WebCore/storage/IDBEvent.cpp | 106 --- Source/WebCore/storage/IDBEvent.h | 62 -- Source/WebCore/storage/IDBEvent.idl | 36 - Source/WebCore/storage/IDBEventDispatcher.cpp | 92 ++ Source/WebCore/storage/IDBEventDispatcher.h | 54 ++ Source/WebCore/storage/IDBFactoryBackendImpl.cpp | 173 +--- Source/WebCore/storage/IDBFactoryBackendImpl.h | 10 +- Source/WebCore/storage/IDBIndex.cpp | 23 +- Source/WebCore/storage/IDBIndex.h | 11 +- Source/WebCore/storage/IDBIndex.idl | 2 +- Source/WebCore/storage/IDBIndexBackendImpl.cpp | 127 +-- Source/WebCore/storage/IDBIndexBackendImpl.h | 27 +- Source/WebCore/storage/IDBKey.cpp | 131 +-- Source/WebCore/storage/IDBKey.h | 12 +- Source/WebCore/storage/IDBKeyPathBackendImpl.cpp | 6 + Source/WebCore/storage/IDBKeyPathBackendImpl.h | 1 + Source/WebCore/storage/IDBKeyRange.cpp | 22 +- Source/WebCore/storage/IDBKeyRange.h | 6 +- Source/WebCore/storage/IDBKeyRange.idl | 2 +- Source/WebCore/storage/IDBObjectStore.cpp | 37 +- .../WebCore/storage/IDBObjectStoreBackendImpl.cpp | 290 ++---- Source/WebCore/storage/IDBObjectStoreBackendImpl.h | 20 +- Source/WebCore/storage/IDBRequest.cpp | 185 +++- Source/WebCore/storage/IDBRequest.h | 32 +- Source/WebCore/storage/IDBRequest.idl | 8 + Source/WebCore/storage/IDBSQLiteDatabase.cpp | 48 - Source/WebCore/storage/IDBSQLiteDatabase.h | 62 -- Source/WebCore/storage/IDBSuccessEvent.cpp | 61 -- Source/WebCore/storage/IDBSuccessEvent.h | 62 -- Source/WebCore/storage/IDBSuccessEvent.idl | 36 - Source/WebCore/storage/IDBTransaction.cpp | 29 +- Source/WebCore/storage/IDBTransaction.h | 5 + .../WebCore/storage/IDBTransactionBackendImpl.cpp | 4 +- Source/WebCore/storage/IDBTransactionBackendImpl.h | 4 +- .../storage/IDBTransactionBackendInterface.h | 2 - .../WebCore/storage/IDBTransactionCoordinator.cpp | 1 - Source/WebCore/storage/IDBVersionChangeEvent.cpp | 58 ++ Source/WebCore/storage/IDBVersionChangeEvent.h | 60 ++ Source/WebCore/storage/IDBVersionChangeEvent.idl | 33 + Source/WebCore/storage/IDBVersionChangeRequest.cpp | 59 ++ Source/WebCore/storage/IDBVersionChangeRequest.h | 54 ++ Source/WebCore/storage/IDBVersionChangeRequest.idl | 34 + .../storage/chromium/IDBKeyPathBackendImpl.cpp | 7 + 74 files changed, 2511 insertions(+), 1802 deletions(-) delete mode 100644 Source/WebCore/storage/IDBAbortEvent.cpp delete mode 100644 Source/WebCore/storage/IDBAbortEvent.h create mode 100644 Source/WebCore/storage/IDBBackingStore.cpp create mode 100644 Source/WebCore/storage/IDBBackingStore.h delete mode 100644 Source/WebCore/storage/IDBCompleteEvent.cpp delete mode 100644 Source/WebCore/storage/IDBCompleteEvent.h create mode 100644 Source/WebCore/storage/IDBCursorWithValue.cpp create mode 100644 Source/WebCore/storage/IDBCursorWithValue.h create mode 100644 Source/WebCore/storage/IDBCursorWithValue.idl create mode 100644 Source/WebCore/storage/IDBDatabaseCallbacks.h delete mode 100644 Source/WebCore/storage/IDBErrorEvent.cpp delete mode 100644 Source/WebCore/storage/IDBErrorEvent.h delete mode 100644 Source/WebCore/storage/IDBErrorEvent.idl delete mode 100644 Source/WebCore/storage/IDBEvent.cpp delete mode 100644 Source/WebCore/storage/IDBEvent.h delete mode 100644 Source/WebCore/storage/IDBEvent.idl create mode 100644 Source/WebCore/storage/IDBEventDispatcher.cpp create mode 100644 Source/WebCore/storage/IDBEventDispatcher.h delete mode 100644 Source/WebCore/storage/IDBSQLiteDatabase.cpp delete mode 100644 Source/WebCore/storage/IDBSQLiteDatabase.h delete mode 100644 Source/WebCore/storage/IDBSuccessEvent.cpp delete mode 100644 Source/WebCore/storage/IDBSuccessEvent.h delete mode 100644 Source/WebCore/storage/IDBSuccessEvent.idl create mode 100644 Source/WebCore/storage/IDBVersionChangeEvent.cpp create mode 100644 Source/WebCore/storage/IDBVersionChangeEvent.h create mode 100644 Source/WebCore/storage/IDBVersionChangeEvent.idl create mode 100644 Source/WebCore/storage/IDBVersionChangeRequest.cpp create mode 100644 Source/WebCore/storage/IDBVersionChangeRequest.h create mode 100644 Source/WebCore/storage/IDBVersionChangeRequest.idl (limited to 'Source/WebCore/storage') diff --git a/Source/WebCore/storage/Database.cpp b/Source/WebCore/storage/Database.cpp index 75f616a..b072edb 100644 --- a/Source/WebCore/storage/Database.cpp +++ b/Source/WebCore/storage/Database.cpp @@ -258,8 +258,10 @@ void Database::changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr callback, PassRefPtr errorCallback, PassRefPtr successCallback) { - m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, ChangeVersionWrapper::create(oldVersion, newVersion))); + RefPtr transaction = + SQLTransaction::create(this, callback, errorCallback, successCallback, ChangeVersionWrapper::create(oldVersion, newVersion)); MutexLocker locker(m_transactionInProgressMutex); + m_transactionQueue.append(transaction.release()); if (!m_transactionInProgress) scheduleTransaction(); } @@ -277,8 +279,10 @@ void Database::readTransaction(PassRefPtr callback, Pass void Database::runTransaction(PassRefPtr callback, PassRefPtr errorCallback, PassRefPtr successCallback, bool readOnly) { - m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, 0, readOnly)); + RefPtr transaction = + SQLTransaction::create(this, callback, errorCallback, successCallback, 0, readOnly); MutexLocker locker(m_transactionInProgressMutex); + m_transactionQueue.append(transaction.release()); if (!m_transactionInProgress) scheduleTransaction(); } diff --git a/Source/WebCore/storage/IDBAbortEvent.cpp b/Source/WebCore/storage/IDBAbortEvent.cpp deleted file mode 100644 index 980d656..0000000 --- a/Source/WebCore/storage/IDBAbortEvent.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBAbortEvent.h" - -#if ENABLE(INDEXED_DATABASE) - -#include "EventNames.h" -#include "IDBAny.h" - -namespace WebCore { - -PassRefPtr IDBAbortEvent::create(PassRefPtr source) -{ - return adoptRef(new IDBAbortEvent(source)); -} - -IDBAbortEvent::IDBAbortEvent(PassRefPtr source) - : IDBEvent(eventNames().abortEvent, source, true) -{ -} - -IDBAbortEvent::~IDBAbortEvent() -{ -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/storage/IDBAbortEvent.h b/Source/WebCore/storage/IDBAbortEvent.h deleted file mode 100644 index fc27989..0000000 --- a/Source/WebCore/storage/IDBAbortEvent.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBAbortEvent_h -#define IDBAbortEvent_h - -#if ENABLE(INDEXED_DATABASE) - -#include "IDBEvent.h" -#include "PlatformString.h" -#include -#include - -namespace WebCore { - -class IDBAbortEvent : public IDBEvent { -public: - static PassRefPtr create(PassRefPtr source); - // FIXME: Need to allow creation of these events from JS. - virtual ~IDBAbortEvent(); - - virtual bool isIDBAbortEvent() const { return true; } - -private: - IDBAbortEvent(PassRefPtr source); -}; - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) - -#endif // IDBAbortEvent_h diff --git a/Source/WebCore/storage/IDBAny.cpp b/Source/WebCore/storage/IDBAny.cpp index 3a049c0..1e076a9 100644 --- a/Source/WebCore/storage/IDBAny.cpp +++ b/Source/WebCore/storage/IDBAny.cpp @@ -28,7 +28,7 @@ #if ENABLE(INDEXED_DATABASE) -#include "IDBCursor.h" +#include "IDBCursorWithValue.h" #include "IDBDatabase.h" #include "IDBFactory.h" #include "IDBIndex.h" @@ -64,6 +64,13 @@ PassRefPtr IDBAny::idbCursor() return m_idbCursor; } + +PassRefPtr IDBAny::idbCursorWithValue() +{ + ASSERT(m_type == IDBCursorWithValueType); + return m_idbCursorWithValue; +} + PassRefPtr IDBAny::idbDatabase() { ASSERT(m_type == IDBDatabaseType); @@ -112,6 +119,13 @@ void IDBAny::setNull() m_type = NullType; } +void IDBAny::set(PassRefPtr value) +{ + ASSERT(m_type == UndefinedType); + m_type = IDBCursorWithValueType; + m_idbCursorWithValue = value; +} + void IDBAny::set(PassRefPtr value) { ASSERT(m_type == UndefinedType); diff --git a/Source/WebCore/storage/IDBAny.h b/Source/WebCore/storage/IDBAny.h index 8e3f83e..e7e94f9 100644 --- a/Source/WebCore/storage/IDBAny.h +++ b/Source/WebCore/storage/IDBAny.h @@ -35,6 +35,7 @@ namespace WebCore { class IDBCursor; +class IDBCursorWithValue; class IDBDatabase; class IDBFactory; class IDBIndex; @@ -67,6 +68,7 @@ public: UndefinedType = 0, NullType, IDBCursorType, + IDBCursorWithValueType, IDBDatabaseType, IDBFactoryType, IDBIndexType, @@ -79,6 +81,7 @@ public: Type type() const { return m_type; } // Use type() to figure out which one of these you're allowed to call. PassRefPtr idbCursor(); + PassRefPtr idbCursorWithValue(); PassRefPtr idbDatabase(); PassRefPtr idbFactory(); PassRefPtr idbIndex(); @@ -90,6 +93,7 @@ public: // Set can only be called once. void setNull(); void set(PassRefPtr); + void set(PassRefPtr); void set(PassRefPtr); void set(PassRefPtr); void set(PassRefPtr); @@ -105,6 +109,7 @@ private: // Only one of the following should ever be in use at any given time. RefPtr m_idbCursor; + RefPtr m_idbCursorWithValue; RefPtr m_idbDatabase; RefPtr m_idbFactory; RefPtr m_idbIndex; diff --git a/Source/WebCore/storage/IDBBackingStore.cpp b/Source/WebCore/storage/IDBBackingStore.cpp new file mode 100644 index 0000000..3859c4c --- /dev/null +++ b/Source/WebCore/storage/IDBBackingStore.cpp @@ -0,0 +1,996 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBBackingStore.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "FileSystem.h" +#include "IDBFactoryBackendImpl.h" +#include "IDBKey.h" +#include "IDBKeyRange.h" +#include "SQLiteDatabase.h" +#include "SQLiteStatement.h" +#include "SQLiteTransaction.h" +#include "SecurityOrigin.h" + +namespace WebCore { + +IDBBackingStore::IDBBackingStore(String identifier, IDBFactoryBackendImpl* factory) + : m_identifier(identifier) + , m_factory(factory) +{ + m_factory->addIDBBackingStore(identifier, this); +} + +IDBBackingStore::~IDBBackingStore() +{ + m_factory->removeIDBBackingStore(m_identifier); +} + +static bool runCommands(SQLiteDatabase& sqliteDatabase, const char** commands, size_t numberOfCommands) +{ + SQLiteTransaction transaction(sqliteDatabase, false); + transaction.begin(); + for (size_t i = 0; i < numberOfCommands; ++i) { + if (!sqliteDatabase.executeCommand(commands[i])) { + LOG_ERROR("Failed to run the following command for IndexedDB: %s", commands[i]); + return false; + } + } + transaction.commit(); + return true; +} + +static bool createTables(SQLiteDatabase& sqliteDatabase) +{ + if (sqliteDatabase.tableExists("Databases")) + return true; + static const char* commands[] = { + "CREATE TABLE Databases (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL)", + "CREATE UNIQUE INDEX Databases_name ON Databases(name)", + + "CREATE TABLE ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL, keyPath TEXT, doAutoIncrement INTEGER NOT NULL, databaseId INTEGER NOT NULL REFERENCES Databases(id))", + "CREATE UNIQUE INDEX ObjectStores_composit ON ObjectStores(databaseId, name)", + + "CREATE TABLE Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT, isUnique INTEGER NOT NULL)", + "CREATE UNIQUE INDEX Indexes_composit ON Indexes(objectStoreId, name)", + + "CREATE TABLE ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, value TEXT NOT NULL)", + "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)", + + "CREATE TABLE IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))", + "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)", + "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDataId)", + "CREATE INDEX IndexData_indexId ON IndexData(indexId)", + }; + + return runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0])); +} + +static bool createMetaDataTable(SQLiteDatabase& sqliteDatabase) +{ + static const char* commands[] = { + "CREATE TABLE MetaData (name TEXT PRIMARY KEY, value NONE)", + "INSERT INTO MetaData VALUES ('version', 1)", + }; + + return runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0])); +} + +static bool getDatabaseSchemaVersion(SQLiteDatabase& sqliteDatabase, int* databaseVersion) +{ + SQLiteStatement query(sqliteDatabase, "SELECT value FROM MetaData WHERE name = 'version'"); + if (query.prepare() != SQLResultOk || query.step() != SQLResultRow) + return false; + + *databaseVersion = query.getColumnInt(0); + return query.finalize() == SQLResultOk; +} + +static bool migrateDatabase(SQLiteDatabase& sqliteDatabase) +{ + if (!sqliteDatabase.tableExists("MetaData")) { + if (!createMetaDataTable(sqliteDatabase)) + return false; + } + + int databaseVersion; + if (!getDatabaseSchemaVersion(sqliteDatabase, &databaseVersion)) + return false; + + if (databaseVersion == 1) { + static const char* commands[] = { + "DROP TABLE IF EXISTS ObjectStoreData2", + "CREATE TABLE ObjectStoreData2 (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate REAL, keyNumber REAL, value TEXT NOT NULL)", + "INSERT INTO ObjectStoreData2 SELECT * FROM ObjectStoreData", + "DROP TABLE ObjectStoreData", // This depends on SQLite not enforcing referential consistency. + "ALTER TABLE ObjectStoreData2 RENAME TO ObjectStoreData", + "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)", + "DROP TABLE IF EXISTS IndexData2", // This depends on SQLite not enforcing referential consistency. + "CREATE TABLE IndexData2 (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate REAL, keyNumber REAL, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))", + "INSERT INTO IndexData2 SELECT * FROM IndexData", + "DROP TABLE IndexData", + "ALTER TABLE IndexData2 RENAME TO IndexData", + "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)", + "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDataId)", + "CREATE INDEX IndexData_indexId ON IndexData(indexId)", + "UPDATE MetaData SET value = 2 WHERE name = 'version'", + }; + + if (!runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0]))) + return false; + + databaseVersion = 2; + } + + if (databaseVersion == 2) { + // We need to make the ObjectStoreData.value be a BLOB instead of TEXT. + static const char* commands[] = { + "DROP TABLE IF EXISTS ObjectStoreData", // This drops associated indices. + "CREATE TABLE ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate REAL, keyNumber REAL, value BLOB NOT NULL)", + "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)", + "UPDATE MetaData SET value = 3 WHERE name = 'version'", + }; + + if (!runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0]))) + return false; + + databaseVersion = 3; + } + + return true; +} + +PassRefPtr IDBBackingStore::open(SecurityOrigin* securityOrigin, const String& pathBase, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl* factory) +{ + RefPtr backingStore(adoptRef(new IDBBackingStore(fileIdentifier, factory))); + + String path = ":memory:"; + if (!pathBase.isEmpty()) { + if (!makeAllDirectories(pathBase)) { + // FIXME: Is there any other thing we could possibly do to recover at this point? If so, do it rather than just erroring out. + LOG_ERROR("Unabled to create LocalStorage database path %s", pathBase.utf8().data()); + return 0; + } + path = pathByAppendingComponent(pathBase, securityOrigin->databaseIdentifier() + ".indexeddb"); + } + + if (!backingStore->m_db.open(path)) { + // FIXME: Is there any other thing we could possibly do to recover at this point? If so, do it rather than just erroring out. + LOG_ERROR("Failed to open database file %s for IndexedDB", path.utf8().data()); + return 0; + } + + // FIXME: Error checking? + backingStore->m_db.setMaximumSize(maximumSize); + backingStore->m_db.turnOnIncrementalAutoVacuum(); + + if (!createTables(backingStore->m_db)) + return 0; + if (!migrateDatabase(backingStore->m_db)) + return 0; + + return backingStore.release(); +} + +bool IDBBackingStore::extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId) +{ + SQLiteStatement databaseQuery(m_db, "SELECT id, version FROM Databases WHERE name = ?"); + if (databaseQuery.prepare() != SQLResultOk) { + ASSERT_NOT_REACHED(); + return false; + } + databaseQuery.bindText(1, name); + if (databaseQuery.step() != SQLResultRow) + return false; + + foundId = databaseQuery.getColumnInt64(0); + foundVersion = databaseQuery.getColumnText(1); + + if (databaseQuery.step() == SQLResultRow) + ASSERT_NOT_REACHED(); + return true; +} + +bool IDBBackingStore::setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId) +{ + ASSERT(!name.isNull()); + ASSERT(!version.isNull()); + + String sql = invalidRowId ? "INSERT INTO Databases (name, description, version) VALUES (?, '', ?)" : "UPDATE Databases SET name = ?, version = ? WHERE id = ?"; + SQLiteStatement query(m_db, sql); + if (query.prepare() != SQLResultOk) { + ASSERT_NOT_REACHED(); + return false; + } + + query.bindText(1, name); + query.bindText(2, version); + if (!invalidRowId) + query.bindInt64(3, rowId); + + if (query.step() != SQLResultDone) + return false; + + if (invalidRowId) + rowId = m_db.lastInsertRowID(); + + return true; +} + +void IDBBackingStore::getObjectStores(int64_t databaseId, Vector& foundIds, Vector& foundNames, Vector& foundKeyPaths, Vector& foundAutoIncrementFlags) +{ + SQLiteStatement query(m_db, "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores WHERE databaseId = ?"); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + ASSERT(foundIds.isEmpty()); + ASSERT(foundNames.isEmpty()); + ASSERT(foundKeyPaths.isEmpty()); + ASSERT(foundAutoIncrementFlags.isEmpty()); + + query.bindInt64(1, databaseId); + + while (query.step() == SQLResultRow) { + foundIds.append(query.getColumnInt64(0)); + foundNames.append(query.getColumnText(1)); + foundKeyPaths.append(query.getColumnText(2)); + foundAutoIncrementFlags.append(!!query.getColumnInt(3)); + } +} + +bool IDBBackingStore::createObjectStore(const String& name, const String& keyPath, bool autoIncrement, int64_t databaseId, int64_t& assignedObjectStoreId) +{ + SQLiteStatement query(m_db, "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement, databaseId) VALUES (?, ?, ?, ?)"); + if (query.prepare() != SQLResultOk) + return false; + + query.bindText(1, name); + query.bindText(2, keyPath); + query.bindInt(3, static_cast(autoIncrement)); + query.bindInt64(4, databaseId); + + if (query.step() != SQLResultDone) + return false; + + assignedObjectStoreId = m_db.lastInsertRowID(); + return true; +} + +static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id) +{ + SQLiteStatement deleteQuery(db, sql); + bool ok = deleteQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + deleteQuery.bindInt64(1, id); + ok = deleteQuery.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. +} + +void IDBBackingStore::deleteObjectStore(int64_t objectStoreId) +{ + doDelete(m_db, "DELETE FROM ObjectStores WHERE id = ?", objectStoreId); + doDelete(m_db, "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStoreId); + doDelete(m_db, "DELETE FROM IndexData WHERE indexId IN (SELECT id FROM Indexes WHERE objectStoreId = ?)", objectStoreId); + doDelete(m_db, "DELETE FROM Indexes WHERE objectStoreId = ?", objectStoreId); +} + +static String whereSyntaxForKey(const IDBKey& key, String qualifiedTableName = "") +{ + switch (key.type()) { + case IDBKey::StringType: + return qualifiedTableName + "keyString = ? AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL "; + case IDBKey::NumberType: + return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber = ? "; + case IDBKey::DateType: + return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate = ? AND " + qualifiedTableName + "keyNumber IS NULL "; + case IDBKey::NullType: + return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL "; + } + + ASSERT_NOT_REACHED(); + return ""; +} + +// Returns the number of items bound. +static int bindKeyToQuery(SQLiteStatement& query, int column, const IDBKey& key) +{ + switch (key.type()) { + case IDBKey::StringType: + query.bindText(column, key.string()); + return 1; + case IDBKey::DateType: + query.bindDouble(column, key.date()); + return 1; + case IDBKey::NumberType: + query.bindDouble(column, key.number()); + return 1; + case IDBKey::NullType: + return 0; + } + + ASSERT_NOT_REACHED(); + return 0; +} + +static String lowerCursorWhereFragment(const IDBKey& key, String comparisonOperator, String qualifiedTableName = "") +{ + switch (key.type()) { + case IDBKey::StringType: + return "? " + comparisonOperator + " " + qualifiedTableName + "keyString AND "; + case IDBKey::DateType: + return "(? " + comparisonOperator + " " + qualifiedTableName + "keyDate OR NOT " + qualifiedTableName + "keyString IS NULL) AND "; + case IDBKey::NumberType: + return "(? " + comparisonOperator + " " + qualifiedTableName + "keyNumber OR NOT " + qualifiedTableName + "keyString IS NULL OR NOT " + qualifiedTableName + "keyDate IS NULL) AND "; + case IDBKey::NullType: + if (comparisonOperator == "<") + return "NOT(" + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL) AND "; + return ""; // If it's =, the upper bound half will do the constraining. If it's <=, then that's a no-op. + } + ASSERT_NOT_REACHED(); + return ""; +} + +static String upperCursorWhereFragment(const IDBKey& key, String comparisonOperator, String qualifiedTableName = "") +{ + switch (key.type()) { + case IDBKey::StringType: + return "(" + qualifiedTableName + "keyString " + comparisonOperator + " ? OR " + qualifiedTableName + "keyString IS NULL) AND "; + case IDBKey::DateType: + return "(" + qualifiedTableName + "keyDate " + comparisonOperator + " ? OR " + qualifiedTableName + "keyDate IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND "; + case IDBKey::NumberType: + return "(" + qualifiedTableName + "keyNumber " + comparisonOperator + " ? OR " + qualifiedTableName + "keyNumber IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND "; + case IDBKey::NullType: + if (comparisonOperator == "<") + return "0 != 0 AND "; + return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL AND "; + } + ASSERT_NOT_REACHED(); + return ""; +} + +String IDBBackingStore::getObjectStoreRecord(int64_t objectStoreId, const IDBKey& key) +{ + SQLiteStatement query(m_db, "SELECT keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE objectStoreId = ? AND " + whereSyntaxForKey(key)); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + query.bindInt64(1, objectStoreId); + bindKeyToQuery(query, 2, key); + if (query.step() != SQLResultRow) + return String(); // Null String means record not found. + + ASSERT((key.type() == IDBKey::StringType) != query.isColumnNull(0)); + ASSERT((key.type() == IDBKey::DateType) != query.isColumnNull(1)); + ASSERT((key.type() == IDBKey::NumberType) != query.isColumnNull(2)); + + String record = query.getColumnBlobAsString(3); + ASSERT(query.step() != SQLResultRow); + + return record; +} + +static void bindKeyToQueryWithNulls(SQLiteStatement& query, int baseColumn, const IDBKey& key) +{ + switch (key.type()) { + case IDBKey::StringType: + query.bindText(baseColumn + 0, key.string()); + query.bindNull(baseColumn + 1); + query.bindNull(baseColumn + 2); + break; + case IDBKey::DateType: + query.bindNull(baseColumn + 0); + query.bindDouble(baseColumn + 1, key.date()); + query.bindNull(baseColumn + 2); + break; + case IDBKey::NumberType: + query.bindNull(baseColumn + 0); + query.bindNull(baseColumn + 1); + query.bindDouble(baseColumn + 2, key.number()); + break; + case IDBKey::NullType: + query.bindNull(baseColumn + 0); + query.bindNull(baseColumn + 1); + query.bindNull(baseColumn + 2); + break; + default: + ASSERT_NOT_REACHED(); + } +} + +bool IDBBackingStore::putObjectStoreRecord(int64_t objectStoreId, const IDBKey& key, const String& value, int64_t& rowId, bool invalidRowId) +{ + String sql = !invalidRowId ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?" + : "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)"; + SQLiteStatement query(m_db, sql); + if (query.prepare() != SQLResultOk) + return false; + + bindKeyToQueryWithNulls(query, 1, key); + query.bindBlob(4, value); + if (!invalidRowId) + query.bindInt64(5, rowId); + else + query.bindInt64(5, objectStoreId); + + if (query.step() != SQLResultDone) + return false; + + if (invalidRowId) + rowId = m_db.lastInsertRowID(); + + return true; +} + +void IDBBackingStore::clearObjectStore(int64_t objectStoreId) +{ + doDelete(m_db, "DELETE FROM IndexData WHERE objectStoreDataId IN (SELECT id FROM ObjectStoreData WHERE objectStoreId = ?)", objectStoreId); + doDelete(m_db, "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStoreId); +} + +void IDBBackingStore::deleteObjectStoreRecord(int64_t, int64_t objectStoreDataId) +{ + SQLiteStatement osQuery(m_db, "DELETE FROM ObjectStoreData WHERE id = ?"); + bool ok = osQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + osQuery.bindInt64(1, objectStoreDataId); + + ok = osQuery.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); + + SQLiteStatement indexQuery(m_db, "DELETE FROM IndexData WHERE objectStoreDataId = ?"); + ok = indexQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + indexQuery.bindInt64(1, objectStoreDataId); + + ok = indexQuery.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); +} + +double IDBBackingStore::nextAutoIncrementNumber(int64_t objectStoreId) +{ + SQLiteStatement query(m_db, "SELECT max(keyNumber) + 1 FROM ObjectStoreData WHERE objectStoreId = ? AND keyString IS NULL AND keyDate IS NULL"); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); + + query.bindInt64(1, objectStoreId); + + if (query.step() != SQLResultRow || query.isColumnNull(0)) + return 1; + + return query.getColumnDouble(0); +} + +bool IDBBackingStore::keyExistsInObjectStore(int64_t objectStoreId, const IDBKey& key, int64_t& foundObjectStoreDataId) +{ + String sql = String("SELECT id FROM ObjectStoreData WHERE objectStoreId = ? AND ") + whereSyntaxForKey(key); + SQLiteStatement query(m_db, sql); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + query.bindInt64(1, objectStoreId); + bindKeyToQuery(query, 2, key); + + if (query.step() != SQLResultRow) + return false; + + foundObjectStoreDataId = query.getColumnInt64(0); + return true; +} + +bool IDBBackingStore::forEachObjectStoreRecord(int64_t objectStoreId, ObjectStoreRecordCallback& callback) +{ + SQLiteStatement query(m_db, "SELECT id, value FROM ObjectStoreData WHERE objectStoreId = ?"); + if (query.prepare() != SQLResultOk) + return false; + + query.bindInt64(1, objectStoreId); + + while (query.step() == SQLResultRow) { + int64_t objectStoreDataId = query.getColumnInt64(0); + String value = query.getColumnBlobAsString(1); + if (!callback.callback(objectStoreDataId, value)) + return false; + } + + return true; +} + +void IDBBackingStore::getIndexes(int64_t objectStoreId, Vector& foundIds, Vector& foundNames, Vector& foundKeyPaths, Vector& foundUniqueFlags) +{ + SQLiteStatement query(m_db, "SELECT id, name, keyPath, isUnique FROM Indexes WHERE objectStoreId = ?"); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + ASSERT(foundIds.isEmpty()); + ASSERT(foundNames.isEmpty()); + ASSERT(foundKeyPaths.isEmpty()); + ASSERT(foundUniqueFlags.isEmpty()); + + query.bindInt64(1, objectStoreId); + + while (query.step() == SQLResultRow) { + foundIds.append(query.getColumnInt64(0)); + foundNames.append(query.getColumnText(1)); + foundKeyPaths.append(query.getColumnText(2)); + foundUniqueFlags.append(!!query.getColumnInt(3)); + } +} + +bool IDBBackingStore::createIndex(int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, int64_t& indexId) +{ + SQLiteStatement query(m_db, "INSERT INTO Indexes (objectStoreId, name, keyPath, isUnique) VALUES (?, ?, ?, ?)"); + if (query.prepare() != SQLResultOk) + return false; + + query.bindInt64(1, objectStoreId); + query.bindText(2, name); + query.bindText(3, keyPath); + query.bindInt(4, static_cast(isUnique)); + + if (query.step() != SQLResultDone) + return false; + + indexId = m_db.lastInsertRowID(); + return true; +} + +void IDBBackingStore::deleteIndex(int64_t indexId) +{ + doDelete(m_db, "DELETE FROM Indexes WHERE id = ?", indexId); + doDelete(m_db, "DELETE FROM IndexData WHERE indexId = ?", indexId); +} + +bool IDBBackingStore::putIndexDataForRecord(int64_t indexId, const IDBKey& key, int64_t objectStoreDataId) +{ + SQLiteStatement query(m_db, "INSERT INTO IndexData (keyString, keyDate, keyNumber, indexId, objectStoreDataId) VALUES (?, ?, ?, ?, ?)"); + if (query.prepare() != SQLResultOk) + return false; + + bindKeyToQueryWithNulls(query, 1, key); + query.bindInt64(4, indexId); + query.bindInt64(5, objectStoreDataId); + + return query.step() == SQLResultDone; +} + +bool IDBBackingStore::deleteIndexDataForRecord(int64_t objectStoreDataId) +{ + SQLiteStatement query(m_db, "DELETE FROM IndexData WHERE objectStoreDataId = ?"); + if (query.prepare() != SQLResultOk) + return false; + + query.bindInt64(1, objectStoreDataId); + return query.step() == SQLResultDone; +} + +String IDBBackingStore::getObjectViaIndex(int64_t indexId, const IDBKey& key) +{ + String sql = String("SELECT ") + + "ObjectStoreData.value " + + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id " + + "WHERE IndexData.indexId = ? AND " + whereSyntaxForKey(key, "IndexData.") + + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails. + SQLiteStatement query(m_db, sql); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + query.bindInt64(1, indexId); + bindKeyToQuery(query, 2, key); + + if (query.step() != SQLResultRow) + return String(); + + String foundValue = query.getColumnBlobAsString(0); + ASSERT(query.step() != SQLResultRow); + return foundValue; +} + +static PassRefPtr keyFromQuery(SQLiteStatement& query, int baseColumn) +{ + if (query.columnCount() <= baseColumn) + return 0; + + if (!query.isColumnNull(baseColumn)) + return IDBKey::createString(query.getColumnText(baseColumn)); + + if (!query.isColumnNull(baseColumn + 1)) + return IDBKey::createDate(query.getColumnDouble(baseColumn + 1)); + + if (!query.isColumnNull(baseColumn + 2)) + return IDBKey::createNumber(query.getColumnDouble(baseColumn + 2)); + + return IDBKey::createNull(); +} + +PassRefPtr IDBBackingStore::getPrimaryKeyViaIndex(int64_t indexId, const IDBKey& key) +{ + String sql = String("SELECT ") + + "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber " + + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id " + + "WHERE IndexData.indexId = ? AND " + whereSyntaxForKey(key, "IndexData.") + + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails. + SQLiteStatement query(m_db, sql); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + query.bindInt64(1, indexId); + bindKeyToQuery(query, 2, key); + + if (query.step() != SQLResultRow) + return 0; + + RefPtr foundKey = keyFromQuery(query, 0); + ASSERT(query.step() != SQLResultRow); + return foundKey.release(); +} + +bool IDBBackingStore::keyExistsInIndex(int64_t indexId, const IDBKey& key) +{ + String sql = String("SELECT id FROM IndexData WHERE indexId = ? AND ") + whereSyntaxForKey(key); + SQLiteStatement query(m_db, sql); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + query.bindInt64(1, indexId); + bindKeyToQuery(query, 2, key); + + return query.step() == SQLResultRow; +} + +namespace { + +class CursorImplCommon : public IDBBackingStore::Cursor { +public: + CursorImplCommon(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint, bool iterateForward) + : m_query(sqliteDatabase, query) + , m_db(sqliteDatabase) + , m_uniquenessConstraint(uniquenessConstraint) + , m_iterateForward(iterateForward) + { + } + virtual ~CursorImplCommon() {} + + // IDBBackingStore::Cursor + virtual bool continueFunction(const IDBKey*); + virtual PassRefPtr key() { return m_currentKey; } + virtual PassRefPtr primaryKey() { return m_currentKey; } + virtual String value() = 0; + virtual int64_t objectStoreDataId() = 0; + virtual int64_t indexDataId() = 0; + + virtual void loadCurrentRow() = 0; + virtual bool currentRowExists() = 0; + + SQLiteStatement m_query; + +protected: + SQLiteDatabase& m_db; + bool m_uniquenessConstraint; + bool m_iterateForward; + int64_t m_currentId; + RefPtr m_currentKey; +}; + +bool CursorImplCommon::continueFunction(const IDBKey* key) +{ + while (true) { + if (m_query.step() != SQLResultRow) + return false; + + RefPtr oldKey = m_currentKey; + loadCurrentRow(); + + // Skip if this entry has been deleted from the object store. + if (!currentRowExists()) + continue; + + // If a key was supplied, we must loop until we find a key greater than or equal to it (or hit the end). + if (key) { + if (m_iterateForward) { + if (m_currentKey->isLessThan(key)) + continue; + } else { + if (key->isLessThan(m_currentKey.get())) + continue; + } + } + + // If we don't have a uniqueness constraint, we can stop now. + if (!m_uniquenessConstraint) + break; + if (!m_currentKey->isEqual(oldKey.get())) + break; + } + + return true; +} + +class ObjectStoreCursorImpl : public CursorImplCommon { +public: + ObjectStoreCursorImpl(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint, bool iterateForward) + : CursorImplCommon(sqliteDatabase, query, uniquenessConstraint, iterateForward) + { + } + + // CursorImplCommon. + virtual String value() { return m_currentValue; } + virtual int64_t objectStoreDataId() { return m_currentId; } + virtual int64_t indexDataId() { ASSERT_NOT_REACHED(); return 0; } + virtual void loadCurrentRow(); + virtual bool currentRowExists(); + +private: + String m_currentValue; +}; + +void ObjectStoreCursorImpl::loadCurrentRow() +{ + m_currentId = m_query.getColumnInt64(0); + m_currentKey = keyFromQuery(m_query, 1); + m_currentValue = m_query.getColumnBlobAsString(4); +} + +bool ObjectStoreCursorImpl::currentRowExists() +{ + String sql = "SELECT id FROM ObjectStoreData WHERE id = ?"; + SQLiteStatement statement(m_db, sql); + + bool ok = statement.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); + + statement.bindInt64(1, m_currentId); + return statement.step() == SQLResultRow; +} + +class IndexKeyCursorImpl : public CursorImplCommon { +public: + IndexKeyCursorImpl(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint, bool iterateForward) + : CursorImplCommon(sqliteDatabase, query, uniquenessConstraint, iterateForward) + { + } + + // CursorImplCommon + virtual PassRefPtr primaryKey() { return m_currentPrimaryKey; } + virtual String value() { ASSERT_NOT_REACHED(); return String(); } + virtual int64_t objectStoreDataId() { ASSERT_NOT_REACHED(); return 0; } + virtual int64_t indexDataId() { return m_currentId; } + virtual void loadCurrentRow(); + virtual bool currentRowExists(); + +private: + RefPtr m_currentPrimaryKey; +}; + +void IndexKeyCursorImpl::loadCurrentRow() +{ + m_currentId = m_query.getColumnInt64(0); + m_currentKey = keyFromQuery(m_query, 1); + m_currentPrimaryKey = keyFromQuery(m_query, 4); +} + +bool IndexKeyCursorImpl::currentRowExists() +{ + String sql = "SELECT id FROM IndexData WHERE id = ?"; + SQLiteStatement statement(m_db, sql); + + bool ok = statement.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); + + statement.bindInt64(1, m_currentId); + return statement.step() == SQLResultRow; +} + +class IndexCursorImpl : public CursorImplCommon { +public: + IndexCursorImpl(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint, bool iterateForward) + : CursorImplCommon(sqliteDatabase, query, uniquenessConstraint, iterateForward) + { + } + + // CursorImplCommon + virtual PassRefPtr primaryKey() { return m_currentPrimaryKey; } + virtual String value() { return m_currentValue; } + virtual int64_t objectStoreDataId() { ASSERT_NOT_REACHED(); return 0; } + virtual int64_t indexDataId() { return m_currentId; } + virtual void loadCurrentRow(); + virtual bool currentRowExists(); + +private: + RefPtr m_currentPrimaryKey; + String m_currentValue; +}; + +void IndexCursorImpl::loadCurrentRow() +{ + m_currentId = m_query.getColumnInt64(0); + m_currentKey = keyFromQuery(m_query, 1); + m_currentValue = m_query.getColumnBlobAsString(4); + m_currentPrimaryKey = keyFromQuery(m_query, 5); +} + +bool IndexCursorImpl::currentRowExists() +{ + String sql = "SELECT id FROM IndexData WHERE id = ?"; + SQLiteStatement statement(m_db, sql); + + bool ok = statement.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); + + statement.bindInt64(1, m_currentId); + return statement.step() == SQLResultRow; +} + +} // namespace + +PassRefPtr IDBBackingStore::openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange* range, IDBCursor::Direction direction) +{ + bool lowerBound = range && range->lower(); + bool upperBound = range && range->upper(); + + String sql = "SELECT id, keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE "; + if (lowerBound) + sql += lowerCursorWhereFragment(*range->lower(), range->lowerOpen() ? "<" : "<="); + if (upperBound) + sql += upperCursorWhereFragment(*range->upper(), range->upperOpen() ? "<" : "<="); + sql += "objectStoreId = ? ORDER BY "; + + if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) + sql += "keyString, keyDate, keyNumber"; + else + sql += "keyString DESC, keyDate DESC, keyNumber DESC"; + + RefPtr cursor = adoptRef(new ObjectStoreCursorImpl(m_db, sql, direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE, + direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT)); + + bool ok = cursor->m_query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + int currentColumn = 1; + if (lowerBound) + currentColumn += bindKeyToQuery(cursor->m_query, currentColumn, *range->lower()); + if (upperBound) + currentColumn += bindKeyToQuery(cursor->m_query, currentColumn, *range->upper()); + cursor->m_query.bindInt64(currentColumn, objectStoreId); + + if (cursor->m_query.step() != SQLResultRow) + return 0; + + cursor->loadCurrentRow(); + return cursor.release(); +} + +PassRefPtr IDBBackingStore::openIndexKeyCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction) +{ + String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ") + + ("ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") + + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE "; + + bool lowerBound = range && range->lower(); + bool upperBound = range && range->upper(); + + if (lowerBound) + sql += lowerCursorWhereFragment(*range->lower(), range->lowerOpen() ? "<" : "<=", "IndexData."); + if (upperBound) + sql += upperCursorWhereFragment(*range->upper(), range->upperOpen() ? "<" : "<=", "IndexData."); + sql += "IndexData.indexId = ? ORDER BY "; + + if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) + sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id"; + else + sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC"; + + RefPtr cursor = adoptRef(new IndexKeyCursorImpl(m_db, sql, direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE, + direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT)); + + bool ok = cursor->m_query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + int indexColumn = 1; + if (lowerBound) + indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->lower()); + if (upperBound) + indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->upper()); + cursor->m_query.bindInt64(indexColumn, indexId); + + if (cursor->m_query.step() != SQLResultRow) + return 0; + + cursor->loadCurrentRow(); + return cursor.release(); +} + +PassRefPtr IDBBackingStore::openIndexCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction) +{ + String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ") + + ("ObjectStoreData.value, ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") + + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE "; + + bool lowerBound = range && range->lower(); + bool upperBound = range && range->upper(); + + if (lowerBound) + sql += lowerCursorWhereFragment(*range->lower(), range->lowerOpen() ? "<" : "<=", "IndexData."); + if (upperBound) + sql += upperCursorWhereFragment(*range->upper(), range->upperOpen() ? "<" : "<=", "IndexData."); + sql += "IndexData.indexId = ? ORDER BY "; + + if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) + sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id"; + else + sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC"; + + RefPtr cursor = adoptRef(new IndexCursorImpl(m_db, sql, direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE, + direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT)); + + bool ok = cursor->m_query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + int indexColumn = 1; + if (lowerBound) + indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->lower()); + if (upperBound) + indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->upper()); + cursor->m_query.bindInt64(indexColumn, indexId); + + if (cursor->m_query.step() != SQLResultRow) + return 0; + + cursor->loadCurrentRow(); + return cursor.release(); +} + +namespace { + +class TransactionImpl : public IDBBackingStore::Transaction { +public: + TransactionImpl(SQLiteDatabase& db) + : m_transaction(db) + { + } + + // IDBBackingStore::Transaction + virtual void begin() { m_transaction.begin(); } + virtual void commit() { m_transaction.commit(); } + virtual void rollback() { m_transaction.rollback(); } + +private: + SQLiteTransaction m_transaction; +}; + +} // namespace + +PassRefPtr IDBBackingStore::createTransaction() +{ + return adoptRef(new TransactionImpl(m_db)); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/storage/IDBBackingStore.h b/Source/WebCore/storage/IDBBackingStore.h new file mode 100644 index 0000000..e75fee1 --- /dev/null +++ b/Source/WebCore/storage/IDBBackingStore.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBBackingStore_h +#define IDBBackingStore_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBCursor.h" +#include "SQLiteDatabase.h" +#include +#include +#include +#include + +namespace WebCore { + +class IDBFactoryBackendImpl; +class IDBKey; +class IDBKeyRange; +class SecurityOrigin; + +class IDBBackingStore : public RefCounted { +public: + static PassRefPtr open(SecurityOrigin*, const String& pathBase, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl*); + ~IDBBackingStore(); + + bool extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId); + bool setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId); + + void getObjectStores(int64_t databaseId, Vector& foundIds, Vector& foundNames, Vector& foundKeyPaths, Vector& foundAutoIncrementFlags); + bool createObjectStore(const String& name, const String& keyPath, bool autoIncrement, int64_t databaseId, int64_t& assignedObjectStoreId); + void deleteObjectStore(int64_t objectStoreId); + String getObjectStoreRecord(int64_t objectStoreId, const IDBKey&); + bool putObjectStoreRecord(int64_t objectStoreId, const IDBKey&, const String& value, int64_t& rowId, bool invalidRowId); + void clearObjectStore(int64_t objectStoreId); + void deleteObjectStoreRecord(int64_t objectStoreId, int64_t objectStoreDataId); + double nextAutoIncrementNumber(int64_t objectStoreId); + bool keyExistsInObjectStore(int64_t objectStoreId, const IDBKey&, int64_t& foundObjectStoreDataId); + + class ObjectStoreRecordCallback { + public: + virtual bool callback(int64_t objectStoreDataId, const String& value) = 0; + virtual ~ObjectStoreRecordCallback() {}; + }; + bool forEachObjectStoreRecord(int64_t objectStoreId, ObjectStoreRecordCallback&); + + void getIndexes(int64_t objectStoreId, Vector& foundIds, Vector& foundNames, Vector& foundKeyPaths, Vector& foundUniqueFlags); + bool createIndex(int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, int64_t& indexId); + void deleteIndex(int64_t indexId); + bool putIndexDataForRecord(int64_t indexId, const IDBKey&, int64_t objectStoreDataId); + bool deleteIndexDataForRecord(int64_t objectStoreDataId); + String getObjectViaIndex(int64_t indexId, const IDBKey&); + PassRefPtr getPrimaryKeyViaIndex(int64_t indexId, const IDBKey&); + bool keyExistsInIndex(int64_t indexId, const IDBKey&); + + class Cursor : public RefCounted { + public: + virtual bool continueFunction(const IDBKey* = 0) = 0; + virtual PassRefPtr key() = 0; + virtual PassRefPtr primaryKey() = 0; + virtual String value() = 0; + virtual int64_t objectStoreDataId() = 0; + virtual int64_t indexDataId() = 0; + virtual ~Cursor() {}; + }; + + PassRefPtr openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange*, IDBCursor::Direction); + PassRefPtr openIndexKeyCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction); + PassRefPtr openIndexCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction); + + class Transaction : public RefCounted { + public: + virtual void begin() = 0; + virtual void commit() = 0; + virtual void rollback() = 0; + }; + PassRefPtr createTransaction(); + +private: + IDBBackingStore(String identifier, IDBFactoryBackendImpl* factory); + + SQLiteDatabase m_db; + String m_identifier; + RefPtr m_factory; +}; + +} // namespace WebCore + +#endif + +#endif // IDBBackingStore_h diff --git a/Source/WebCore/storage/IDBCallbacks.h b/Source/WebCore/storage/IDBCallbacks.h index 29fb1c4..f4e1b98 100644 --- a/Source/WebCore/storage/IDBCallbacks.h +++ b/Source/WebCore/storage/IDBCallbacks.h @@ -53,9 +53,9 @@ public: virtual void onSuccess(PassRefPtr) = 0; virtual void onSuccess(PassRefPtr) = 0; virtual void onSuccess(PassRefPtr) = 0; - virtual void onSuccess(PassRefPtr) = 0; virtual void onSuccess(PassRefPtr) = 0; virtual void onSuccess(PassRefPtr) = 0; + virtual void onBlocked() = 0; }; } // namespace WebCore diff --git a/Source/WebCore/storage/IDBCompleteEvent.cpp b/Source/WebCore/storage/IDBCompleteEvent.cpp deleted file mode 100644 index 20ee57a..0000000 --- a/Source/WebCore/storage/IDBCompleteEvent.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBCompleteEvent.h" - -#if ENABLE(INDEXED_DATABASE) - -#include "EventNames.h" -#include "IDBAny.h" - -namespace WebCore { - -PassRefPtr IDBCompleteEvent::create(PassRefPtr source) -{ - return adoptRef(new IDBCompleteEvent(source)); -} - -IDBCompleteEvent::IDBCompleteEvent(PassRefPtr source) - : IDBEvent(eventNames().completeEvent, source, false) -{ -} - -IDBCompleteEvent::~IDBCompleteEvent() -{ -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/storage/IDBCompleteEvent.h b/Source/WebCore/storage/IDBCompleteEvent.h deleted file mode 100644 index c004a72..0000000 --- a/Source/WebCore/storage/IDBCompleteEvent.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBCompleteEvent_h -#define IDBCompleteEvent_h - -#if ENABLE(INDEXED_DATABASE) - -#include "IDBEvent.h" -#include "PlatformString.h" -#include -#include - -namespace WebCore { - -class IDBCompleteEvent : public IDBEvent { -public: - static PassRefPtr create(PassRefPtr source); - // FIXME: Need to allow creation of these events from JS. - virtual ~IDBCompleteEvent(); - - virtual bool isIDBCompleteEvent() const { return true; } - -private: - IDBCompleteEvent(PassRefPtr source); -}; - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) - -#endif // IDBCompleteEvent_h diff --git a/Source/WebCore/storage/IDBCursor.cpp b/Source/WebCore/storage/IDBCursor.cpp index 531cae1..9b1ebf6 100644 --- a/Source/WebCore/storage/IDBCursor.cpp +++ b/Source/WebCore/storage/IDBCursor.cpp @@ -39,13 +39,20 @@ namespace WebCore { -IDBCursor::IDBCursor(PassRefPtr backend, IDBRequest* request, IDBTransaction* transaction) +PassRefPtr IDBCursor::create(PassRefPtr backend, IDBRequest* request, IDBAny* source, IDBTransaction* transaction) +{ + return adoptRef(new IDBCursor(backend, request, source, transaction)); +} + +IDBCursor::IDBCursor(PassRefPtr backend, IDBRequest* request, IDBAny* source, IDBTransaction* transaction) : m_backend(backend) , m_request(request) + , m_source(source) , m_transaction(transaction) { ASSERT(m_backend); ASSERT(m_request); + ASSERT(m_source->type() == IDBAny::IDBObjectStoreType || m_source->type() == IDBAny::IDBIndexType); ASSERT(m_transaction); } @@ -63,17 +70,29 @@ PassRefPtr IDBCursor::key() const return m_backend->key(); } -PassRefPtr IDBCursor::value() const +PassRefPtr IDBCursor::primaryKey() const +{ + return m_backend->primaryKey(); +} + +PassRefPtr IDBCursor::value() const { return m_backend->value(); } +IDBAny* IDBCursor::source() const +{ + return m_source.get(); +} + PassRefPtr IDBCursor::update(ScriptExecutionContext* context, PassRefPtr value, ExceptionCode& ec) { RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); m_backend->update(value, request, ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; + } return request.release(); } @@ -91,8 +110,10 @@ PassRefPtr IDBCursor::deleteFunction(ScriptExecutionContext* context { RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); m_backend->deleteFunction(request, ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; + } return request.release(); } diff --git a/Source/WebCore/storage/IDBCursor.h b/Source/WebCore/storage/IDBCursor.h index 9f5ffad..9ade9c8 100644 --- a/Source/WebCore/storage/IDBCursor.h +++ b/Source/WebCore/storage/IDBCursor.h @@ -29,6 +29,7 @@ #if ENABLE(INDEXED_DATABASE) #include "ExceptionCode.h" +#include "IDBKey.h" #include #include #include @@ -38,7 +39,6 @@ namespace WebCore { class IDBAny; class IDBCallbacks; class IDBCursorBackendInterface; -class IDBKey; class IDBRequest; class IDBTransaction; class ScriptExecutionContext; @@ -52,11 +52,8 @@ public: PREV = 2, PREV_NO_DUPLICATE = 3, }; - static PassRefPtr create(PassRefPtr backend, IDBRequest* request, IDBTransaction* transaction) - { - return adoptRef(new IDBCursor(backend, request, transaction)); - } - ~IDBCursor(); + static PassRefPtr create(PassRefPtr, IDBRequest*, IDBAny* source, IDBTransaction*); + virtual ~IDBCursor(); // FIXME: Try to modify the code generator so this is unneeded. void continueFunction(ExceptionCode& ec) { continueFunction(0, ec); } @@ -64,16 +61,21 @@ public: // Implement the IDL unsigned short direction() const; PassRefPtr key() const; - PassRefPtr value() const; + PassRefPtr primaryKey() const; + PassRefPtr value() const; + IDBAny* source() const; + PassRefPtr update(ScriptExecutionContext*, PassRefPtr, ExceptionCode&); void continueFunction(PassRefPtr, ExceptionCode&); PassRefPtr deleteFunction(ScriptExecutionContext*, ExceptionCode&); -private: - explicit IDBCursor(PassRefPtr, IDBRequest*, IDBTransaction*); +protected: + IDBCursor(PassRefPtr, IDBRequest*, IDBAny* source, IDBTransaction*); +private: RefPtr m_backend; RefPtr m_request; + RefPtr m_source; RefPtr m_transaction; }; diff --git a/Source/WebCore/storage/IDBCursor.idl b/Source/WebCore/storage/IDBCursor.idl index 2e1459f..1f44cd2 100644 --- a/Source/WebCore/storage/IDBCursor.idl +++ b/Source/WebCore/storage/IDBCursor.idl @@ -35,7 +35,8 @@ module storage { readonly attribute unsigned short direction; readonly attribute IDBKey key; - readonly attribute IDBAny value; + readonly attribute IDBKey primaryKey; + readonly attribute IDBAny source; [CallWith=ScriptExecutionContext] IDBRequest update(in SerializedScriptValue value) raises (IDBDatabaseException); diff --git a/Source/WebCore/storage/IDBCursorBackendImpl.cpp b/Source/WebCore/storage/IDBCursorBackendImpl.cpp index 089bb67..6ae3616 100644 --- a/Source/WebCore/storage/IDBCursorBackendImpl.cpp +++ b/Source/WebCore/storage/IDBCursorBackendImpl.cpp @@ -29,32 +29,25 @@ #if ENABLE(INDEXED_DATABASE) #include "CrossThreadTask.h" +#include "IDBBackingStore.h" #include "IDBCallbacks.h" -#include "IDBDatabaseBackendImpl.h" #include "IDBDatabaseError.h" #include "IDBDatabaseException.h" -#include "IDBIndexBackendImpl.h" #include "IDBKeyRange.h" #include "IDBObjectStoreBackendImpl.h" #include "IDBRequest.h" -#include "IDBSQLiteDatabase.h" #include "IDBTransactionBackendInterface.h" -#include "SQLiteDatabase.h" -#include "SQLiteStatement.h" #include "SerializedScriptValue.h" namespace WebCore { -IDBCursorBackendImpl::IDBCursorBackendImpl(IDBSQLiteDatabase* database, PassRefPtr keyRange, IDBCursor::Direction direction, PassOwnPtr query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore) - : m_database(database) - , m_keyRange(keyRange) +IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr cursor, IDBCursor::Direction direction, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore) + : m_cursor(cursor) , m_direction(direction) - , m_query(query) - , m_isSerializedScriptValueCursor(isSerializedScriptValueCursor) + , m_cursorType(cursorType) , m_transaction(transaction) , m_objectStore(objectStore) { - loadCurrentRow(); } IDBCursorBackendImpl::~IDBCursorBackendImpl() @@ -68,25 +61,28 @@ unsigned short IDBCursorBackendImpl::direction() const PassRefPtr IDBCursorBackendImpl::key() const { - return m_currentKey; + return m_cursor->key(); } -PassRefPtr IDBCursorBackendImpl::value() const +PassRefPtr IDBCursorBackendImpl::primaryKey() const { - if (m_isSerializedScriptValueCursor) - return IDBAny::create(m_currentSerializedScriptValue.get()); - return IDBAny::create(m_currentIDBKeyValue.get()); + return m_cursor->primaryKey(); +} + +PassRefPtr IDBCursorBackendImpl::value() const +{ + ASSERT(m_cursorType != IndexKeyCursor); + return SerializedScriptValue::createFromWire(m_cursor->value()); } void IDBCursorBackendImpl::update(PassRefPtr value, PassRefPtr callbacks, ExceptionCode& ec) { - if (!m_query || m_currentId == InvalidId || !m_isSerializedScriptValueCursor) { + if (!m_cursor || m_cursorType == IndexKeyCursor) { ec = IDBDatabaseException::NOT_ALLOWED_ERR; return; } - RefPtr key = m_currentIDBKeyValue ? m_currentIDBKeyValue : m_currentKey; - m_objectStore->put(value, key.release(), IDBObjectStoreBackendInterface::CursorUpdate, callbacks, m_transaction.get(), ec); + m_objectStore->put(value, m_cursor->primaryKey(), IDBObjectStoreBackendInterface::CursorUpdate, callbacks, m_transaction.get(), ec); } void IDBCursorBackendImpl::continueFunction(PassRefPtr prpKey, PassRefPtr prpCallbacks, ExceptionCode& ec) @@ -98,51 +94,17 @@ void IDBCursorBackendImpl::continueFunction(PassRefPtr prpKey, PassRefPt ec = IDBDatabaseException::NOT_ALLOWED_ERR; } -bool IDBCursorBackendImpl::currentRowExists() -{ - String sql = m_currentIDBKeyValue ? "SELECT id FROM IndexData WHERE id = ?" : "SELECT id FROM ObjectStoreData WHERE id = ?"; - SQLiteStatement statement(m_database->db(), sql); - - bool ok = statement.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); - - statement.bindInt64(1, m_currentId); - return statement.step() == SQLResultRow; -} - // IMPORTANT: If this ever 1) fires an 'error' event and 2) it's possible to fire another event afterwards, // IDBRequest::hasPendingActivity() will need to be modified to handle this!!! void IDBCursorBackendImpl::continueFunctionInternal(ScriptExecutionContext*, PassRefPtr prpCursor, PassRefPtr prpKey, PassRefPtr callbacks) { RefPtr cursor = prpCursor; RefPtr key = prpKey; - while (true) { - if (!cursor->m_query || cursor->m_query->step() != SQLResultRow) { - cursor->m_query = 0; - cursor->m_currentId = InvalidId; - cursor->m_currentKey = 0; - cursor->m_currentSerializedScriptValue = 0; - cursor->m_currentIDBKeyValue = 0; - callbacks->onSuccess(SerializedScriptValue::nullValue()); - return; - } - - RefPtr oldKey = cursor->m_currentKey; - cursor->loadCurrentRow(); - - // Skip if this entry has been deleted from the object store. - if (!cursor->currentRowExists()) - continue; - - // If a key was supplied, we must loop until we find that key (or hit the end). - if (key && !key->isEqual(cursor->m_currentKey.get())) - continue; - - // If we don't have a uniqueness constraint, we can stop now. - if (cursor->m_direction == IDBCursor::NEXT || cursor->m_direction == IDBCursor::PREV) - break; - if (!cursor->m_currentKey->isEqual(oldKey.get())) - break; + + if (!cursor->m_cursor || !cursor->m_cursor->continueFunction(key.get())) { + cursor->m_cursor = 0; + callbacks->onSuccess(SerializedScriptValue::nullValue()); + return; } callbacks->onSuccess(cursor.get()); @@ -150,31 +112,12 @@ void IDBCursorBackendImpl::continueFunctionInternal(ScriptExecutionContext*, Pas void IDBCursorBackendImpl::deleteFunction(PassRefPtr prpCallbacks, ExceptionCode& ec) { - if (!m_query || m_currentId == InvalidId || !m_isSerializedScriptValueCursor) { + if (!m_cursor || m_cursorType == IndexKeyCursor) { ec = IDBDatabaseException::NOT_ALLOWED_ERR; return; } - RefPtr key = m_currentIDBKeyValue ? m_currentIDBKeyValue : m_currentKey; - m_objectStore->deleteFunction(key.release(), prpCallbacks, m_transaction.get(), ec); -} - - -void IDBCursorBackendImpl::loadCurrentRow() -{ - // The column numbers depend on the query in IDBObjectStoreBackendImpl::openCursorInternal or - // IDBIndexBackendImpl::openCursorInternal. - m_currentId = m_query->getColumnInt64(0); - m_currentKey = IDBKey::fromQuery(*m_query, 1); - if (m_isSerializedScriptValueCursor) - m_currentSerializedScriptValue = SerializedScriptValue::createFromWire(m_query->getColumnBlobAsString(4)); - - m_currentIDBKeyValue = IDBKey::fromQuery(*m_query, 5); -} - -SQLiteDatabase& IDBCursorBackendImpl::database() const -{ - return m_database->db(); + m_objectStore->deleteFunction(m_cursor->primaryKey(), prpCallbacks, m_transaction.get(), ec); } } // namespace WebCore diff --git a/Source/WebCore/storage/IDBCursorBackendImpl.h b/Source/WebCore/storage/IDBCursorBackendImpl.h index f459139..2ce3881 100644 --- a/Source/WebCore/storage/IDBCursorBackendImpl.h +++ b/Source/WebCore/storage/IDBCursorBackendImpl.h @@ -29,6 +29,7 @@ #if ENABLE(INDEXED_DATABASE) +#include "IDBBackingStore.h" #include "IDBCursor.h" #include "IDBCursorBackendInterface.h" #include @@ -41,56 +42,34 @@ class IDBDatabaseBackendImpl; class IDBIndexBackendImpl; class IDBKeyRange; class IDBObjectStoreBackendInterface; -class IDBSQLiteDatabase; +class IDBBackingStore; class IDBTransactionBackendInterface; -class SQLiteDatabase; -class SQLiteStatement; class SerializedScriptValue; class IDBCursorBackendImpl : public IDBCursorBackendInterface { public: - static PassRefPtr create(IDBSQLiteDatabase* database, PassRefPtr keyRange, IDBCursor::Direction direction, PassOwnPtr query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore) + static PassRefPtr create(PassRefPtr cursor, IDBCursor::Direction direction, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore) { - return adoptRef(new IDBCursorBackendImpl(database, keyRange, direction, query, isSerializedScriptValueCursor, transaction, objectStore)); + return adoptRef(new IDBCursorBackendImpl(cursor, direction, cursorType, transaction, objectStore)); } virtual ~IDBCursorBackendImpl(); virtual unsigned short direction() const; virtual PassRefPtr key() const; - virtual PassRefPtr value() const; + virtual PassRefPtr primaryKey() const; + virtual PassRefPtr value() const; virtual void update(PassRefPtr, PassRefPtr, ExceptionCode&); virtual void continueFunction(PassRefPtr, PassRefPtr, ExceptionCode&); virtual void deleteFunction(PassRefPtr, ExceptionCode&); private: - IDBCursorBackendImpl(IDBSQLiteDatabase*, PassRefPtr, IDBCursor::Direction, PassOwnPtr query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface*, IDBObjectStoreBackendInterface*); - - bool currentRowExists(); - void loadCurrentRow(); - SQLiteDatabase& database() const; + IDBCursorBackendImpl(PassRefPtr, IDBCursor::Direction, CursorType, IDBTransactionBackendInterface*, IDBObjectStoreBackendInterface*); static void continueFunctionInternal(ScriptExecutionContext*, PassRefPtr, PassRefPtr, PassRefPtr); - static const int64_t InvalidId = -1; - - RefPtr m_database; - - RefPtr m_keyRange; + RefPtr m_cursor; IDBCursor::Direction m_direction; - OwnPtr m_query; - bool m_isSerializedScriptValueCursor; - int64_t m_currentId; - - // The key in the objectStore or index that this cursor iterates over. - RefPtr m_currentKey; - - // m_isSerializedScriptValueCursor will only be available for object cursors. - RefPtr m_currentSerializedScriptValue; - - // FIXME: make the primary key available via script for all types of cursors. - // For cursors on indices, this is the key in the objectstore that corresponds to the current entry in the index. - RefPtr m_currentIDBKeyValue; - + CursorType m_cursorType; RefPtr m_transaction; RefPtr m_objectStore; }; diff --git a/Source/WebCore/storage/IDBCursorBackendInterface.h b/Source/WebCore/storage/IDBCursorBackendInterface.h index 0d132ca..6cdab42 100644 --- a/Source/WebCore/storage/IDBCursorBackendInterface.h +++ b/Source/WebCore/storage/IDBCursorBackendInterface.h @@ -45,9 +45,17 @@ class IDBCursorBackendInterface : public ThreadSafeShared key() const = 0; - virtual PassRefPtr value() const = 0; + virtual PassRefPtr primaryKey() const = 0; + virtual PassRefPtr value() const = 0; virtual void update(PassRefPtr, PassRefPtr, ExceptionCode&) = 0; virtual void continueFunction(PassRefPtr key, PassRefPtr, ExceptionCode&) = 0; diff --git a/Source/WebCore/storage/IDBCursorWithValue.cpp b/Source/WebCore/storage/IDBCursorWithValue.cpp new file mode 100644 index 0000000..d3c3bd8 --- /dev/null +++ b/Source/WebCore/storage/IDBCursorWithValue.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBCursorWithValue.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBCursorBackendInterface.h" +#include "IDBKey.h" + +namespace WebCore { + +PassRefPtr IDBCursorWithValue::create(PassRefPtr backend, IDBRequest* request, IDBAny* source, IDBTransaction* transaction) +{ + return adoptRef(new IDBCursorWithValue(backend, request, source, transaction)); +} + +IDBCursorWithValue::IDBCursorWithValue(PassRefPtr backend, IDBRequest* request, IDBAny* source, IDBTransaction* transaction) + : IDBCursor(backend, request, source, transaction) +{ +} + +IDBCursorWithValue::~IDBCursorWithValue() +{ +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/storage/IDBCursorWithValue.h b/Source/WebCore/storage/IDBCursorWithValue.h new file mode 100644 index 0000000..d0610bd --- /dev/null +++ b/Source/WebCore/storage/IDBCursorWithValue.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBCursorWithValue_h +#define IDBCursorWithValue_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBCursor.h" + +namespace WebCore { + +class IDBCursorWithValue : public IDBCursor { +public: + static PassRefPtr create(PassRefPtr, IDBRequest*, IDBAny* source, IDBTransaction*); + virtual ~IDBCursorWithValue(); + + // The value attribute defined in the IDL is simply implemented in IDBCursor (but not exposed via + // its IDL). This is to make the implementation more simple while matching what the spec says. + +private: + IDBCursorWithValue(PassRefPtr, IDBRequest*, IDBAny* source, IDBTransaction*); +}; + +} // namespace WebCore + +#endif + +#endif // IDBCursorWithValue_h diff --git a/Source/WebCore/storage/IDBCursorWithValue.idl b/Source/WebCore/storage/IDBCursorWithValue.idl new file mode 100644 index 0000000..811215a --- /dev/null +++ b/Source/WebCore/storage/IDBCursorWithValue.idl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE + ] IDBCursorWithValue : IDBCursor { + readonly attribute SerializedScriptValue value; + }; +} diff --git a/Source/WebCore/storage/IDBDatabase.cpp b/Source/WebCore/storage/IDBDatabase.cpp index 9a5eb6c..fe8d350 100644 --- a/Source/WebCore/storage/IDBDatabase.cpp +++ b/Source/WebCore/storage/IDBDatabase.cpp @@ -26,13 +26,17 @@ #include "config.h" #include "IDBDatabase.h" +#include "Document.h" +#include "EventQueue.h" #include "IDBAny.h" #include "IDBDatabaseError.h" #include "IDBDatabaseException.h" +#include "IDBEventDispatcher.h" #include "IDBFactoryBackendInterface.h" #include "IDBIndex.h" #include "IDBObjectStore.h" -#include "IDBRequest.h" +#include "IDBVersionChangeEvent.h" +#include "IDBVersionChangeRequest.h" #include "IDBTransaction.h" #include "ScriptExecutionContext.h" #include @@ -58,7 +62,6 @@ IDBDatabase::IDBDatabase(ScriptExecutionContext* context, PassRefPtrdeleteObjectStore(name, m_setVersionTransaction->backend(), ec); } -PassRefPtr IDBDatabase::setVersion(ScriptExecutionContext* context, const String& version, ExceptionCode& ec) +PassRefPtr IDBDatabase::setVersion(ScriptExecutionContext* context, const String& version, ExceptionCode& ec) { - RefPtr request = IDBRequest::create(context, IDBAny::create(this), 0); - m_backend->setVersion(version, request, ec); + RefPtr request = IDBVersionChangeRequest::create(context, IDBAny::create(this), version); + m_backend->setVersion(version, request, this, ec); return request; } @@ -136,7 +139,27 @@ PassRefPtr IDBDatabase::transaction(ScriptExecutionContext* cont void IDBDatabase::close() { + if (m_noNewTransactions) + return; + + ASSERT(scriptExecutionContext()->isDocument()); + EventQueue* eventQueue = static_cast(scriptExecutionContext())->eventQueue(); + // Remove any pending versionchange events scheduled to fire on this + // connection. They would have been scheduled by the backend when another + // connection called setVersion, but the frontend connection is being + // closed before they could fire. + for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) { + bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get()); + ASSERT_UNUSED(removed, removed); + } + m_noNewTransactions = true; + m_backend->close(this); +} + +void IDBDatabase::onVersionChange(const String& version) +{ + enqueueEvent(IDBVersionChangeEvent::create(version, eventNames().versionchangeEvent)); } bool IDBDatabase::hasPendingActivity() const @@ -149,6 +172,30 @@ bool IDBDatabase::hasPendingActivity() const return !m_stopped || ActiveDOMObject::hasPendingActivity(); } +void IDBDatabase::open() +{ + m_backend->open(this); +} + +void IDBDatabase::enqueueEvent(PassRefPtr event) +{ + ASSERT(scriptExecutionContext()->isDocument()); + EventQueue* eventQueue = static_cast(scriptExecutionContext())->eventQueue(); + event->setTarget(this); + eventQueue->enqueueEvent(event.get()); + m_enqueuedEvents.append(event); +} + +bool IDBDatabase::dispatchEvent(PassRefPtr event) +{ + ASSERT(event->type() == eventNames().versionchangeEvent); + for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) { + if (m_enqueuedEvents[i].get() == event.get()) + m_enqueuedEvents.remove(i); + } + return EventTarget::dispatchEvent(event.get()); +} + void IDBDatabase::stop() { // Stop fires at a deterministic time, so we need to call close in it. diff --git a/Source/WebCore/storage/IDBDatabase.h b/Source/WebCore/storage/IDBDatabase.h index f90ddd3..51f1d23 100644 --- a/Source/WebCore/storage/IDBDatabase.h +++ b/Source/WebCore/storage/IDBDatabase.h @@ -32,6 +32,7 @@ #include "EventTarget.h" #include "ExceptionCode.h" #include "IDBDatabaseBackendInterface.h" +#include "IDBDatabaseCallbacks.h" #include "IDBObjectStore.h" #include "IDBTransaction.h" #include "OptionsObject.h" @@ -43,10 +44,10 @@ namespace WebCore { -class IDBAny; -class IDBRequest; +class IDBVersionChangeRequest; +class ScriptExecutionContext; -class IDBDatabase : public RefCounted, public EventTarget, public ActiveDOMObject { +class IDBDatabase : public IDBDatabaseCallbacks, public EventTarget, public ActiveDOMObject { public: static PassRefPtr create(ScriptExecutionContext*, PassRefPtr); ~IDBDatabase(); @@ -66,11 +67,15 @@ public: PassRefPtr createObjectStore(const String& name, const OptionsObject&, ExceptionCode&); void deleteObjectStore(const String& name, ExceptionCode&); - PassRefPtr setVersion(ScriptExecutionContext*, const String& version, ExceptionCode&); + PassRefPtr setVersion(ScriptExecutionContext*, const String& version, ExceptionCode&); void close(); DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + DEFINE_ATTRIBUTE_EVENT_LISTENER(versionchange); + + // IDBDatabaseCallbacks + virtual void onVersionChange(const String& requestedVersion); // ActiveDOMObject virtual bool hasPendingActivity() const; @@ -80,8 +85,14 @@ public: virtual IDBDatabase* toIDBDatabase() { return this; } virtual ScriptExecutionContext* scriptExecutionContext() const; - using RefCounted::ref; - using RefCounted::deref; + + void open(); + void enqueueEvent(PassRefPtr); + bool dispatchEvent(PassRefPtr event, ExceptionCode& ec) { return EventTarget::dispatchEvent(event, ec); } + virtual bool dispatchEvent(PassRefPtr); + + using RefCounted::ref; + using RefCounted::deref; private: IDBDatabase(ScriptExecutionContext*, PassRefPtr); @@ -99,6 +110,10 @@ private: bool m_stopped; EventTargetData m_eventTargetData; + + // Keep track of the versionchange events waiting to be fired on this + // database so that we can cancel them if the database closes. + Vector > m_enqueuedEvents; }; } // namespace WebCore diff --git a/Source/WebCore/storage/IDBDatabase.idl b/Source/WebCore/storage/IDBDatabase.idl index 3922144..a07fda7 100644 --- a/Source/WebCore/storage/IDBDatabase.idl +++ b/Source/WebCore/storage/IDBDatabase.idl @@ -35,12 +35,13 @@ module storage { attribute EventListener onabort; attribute EventListener onerror; + attribute EventListener onversionchange; IDBObjectStore createObjectStore(in DOMString name, in [Optional] OptionsObject options) raises (IDBDatabaseException); void deleteObjectStore(in DOMString name) raises (IDBDatabaseException); - [CallWith=ScriptExecutionContext] IDBRequest setVersion(in DOMString version) + [CallWith=ScriptExecutionContext] IDBVersionChangeRequest setVersion(in DOMString version) raises (IDBDatabaseException); [CallWith=ScriptExecutionContext] IDBTransaction transaction(in [Optional] DOMStringList storeNames, in [Optional] unsigned short mode) raises (IDBDatabaseException); @@ -53,7 +54,7 @@ module storage { void removeEventListener(in DOMString type, in EventListener listener, in boolean useCapture); - boolean dispatchEvent(in Event evt) + boolean dispatchEvent(in Event evt) raises(EventException); }; diff --git a/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp b/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp index 133c5ae..94e305b 100644 --- a/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp +++ b/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp @@ -30,65 +30,39 @@ #include "CrossThreadTask.h" #include "DOMStringList.h" +#include "IDBBackingStore.h" #include "IDBDatabaseException.h" #include "IDBFactoryBackendImpl.h" #include "IDBObjectStoreBackendImpl.h" -#include "IDBSQLiteDatabase.h" #include "IDBTransactionBackendImpl.h" #include "IDBTransactionCoordinator.h" -#include "SQLiteStatement.h" -#include "SQLiteTransaction.h" namespace WebCore { -static bool extractMetaData(SQLiteDatabase& sqliteDatabase, const String& name, String& foundVersion, int64& foundId) -{ - SQLiteStatement databaseQuery(sqliteDatabase, "SELECT id, version FROM Databases WHERE name = ?"); - if (databaseQuery.prepare() != SQLResultOk) { - ASSERT_NOT_REACHED(); - return false; +class IDBDatabaseBackendImpl::PendingSetVersionCall : public RefCounted { +public: + static PassRefPtr create(const String& version, PassRefPtr callbacks, PassRefPtr databaseCallbacks) + { + return adoptRef(new PendingSetVersionCall(version, callbacks, databaseCallbacks)); } - databaseQuery.bindText(1, name); - if (databaseQuery.step() != SQLResultRow) - return false; - - foundId = databaseQuery.getColumnInt64(0); - foundVersion = databaseQuery.getColumnText(1); - - if (databaseQuery.step() == SQLResultRow) - ASSERT_NOT_REACHED(); - return true; -} - -static bool setMetaData(SQLiteDatabase& sqliteDatabase, const String& name, const String& version, int64_t& rowId) -{ - ASSERT(!name.isNull()); - ASSERT(!version.isNull()); - - String sql = rowId != IDBDatabaseBackendImpl::InvalidId ? "UPDATE Databases SET name = ?, version = ? WHERE id = ?" - : "INSERT INTO Databases (name, description, version) VALUES (?, '', ?)"; - SQLiteStatement query(sqliteDatabase, sql); - if (query.prepare() != SQLResultOk) { - ASSERT_NOT_REACHED(); - return false; + String version() { return m_version; } + PassRefPtr callbacks() { return m_callbacks; } + PassRefPtr databaseCallbacks() { return m_databaseCallbacks; } + +private: + PendingSetVersionCall(const String& version, PassRefPtr callbacks, PassRefPtr databaseCallbacks) + : m_version(version) + , m_callbacks(callbacks) + , m_databaseCallbacks(databaseCallbacks) + { } + String m_version; + RefPtr m_callbacks; + RefPtr m_databaseCallbacks; +}; - query.bindText(1, name); - query.bindText(2, version); - if (rowId != IDBDatabaseBackendImpl::InvalidId) - query.bindInt64(3, rowId); - - if (query.step() != SQLResultDone) - return false; - - if (rowId == IDBDatabaseBackendImpl::InvalidId) - rowId = sqliteDatabase.lastInsertRowID(); - - return true; -} - -IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBSQLiteDatabase* sqliteDatabase, IDBTransactionCoordinator* coordinator, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier) - : m_sqliteDatabase(sqliteDatabase) +IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBBackingStore* backingStore, IDBTransactionCoordinator* coordinator, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier) + : m_backingStore(backingStore) , m_id(InvalidId) , m_name(name) , m_version("") @@ -98,9 +72,9 @@ IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBSQLiteData { ASSERT(!m_name.isNull()); - bool success = extractMetaData(m_sqliteDatabase->db(), m_name, m_version, m_id); + bool success = m_backingStore->extractIDBDatabaseMetaData(m_name, m_version, m_id); ASSERT_UNUSED(success, success == (m_id != InvalidId)); - if (!setMetaData(m_sqliteDatabase->db(), m_name, m_version, m_id)) + if (!m_backingStore->setIDBDatabaseMetaData(m_name, m_version, m_id, m_id == InvalidId)) ASSERT_NOT_REACHED(); // FIXME: Need better error handling. loadObjectStores(); } @@ -110,9 +84,9 @@ IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl() m_factory->removeIDBDatabaseBackend(m_identifier); } -SQLiteDatabase& IDBDatabaseBackendImpl::sqliteDatabase() const +PassRefPtr IDBDatabaseBackendImpl::backingStore() const { - return m_sqliteDatabase->db(); + return m_backingStore; } PassRefPtr IDBDatabaseBackendImpl::objectStoreNames() const @@ -132,7 +106,7 @@ PassRefPtr IDBDatabaseBackendImpl::createObject return 0; } - RefPtr objectStore = IDBObjectStoreBackendImpl::create(m_sqliteDatabase.get(), name, keyPath, autoIncrement); + RefPtr objectStore = IDBObjectStoreBackendImpl::create(m_backingStore.get(), name, keyPath, autoIncrement); ASSERT(objectStore->name() == name); RefPtr database = this; @@ -149,21 +123,14 @@ PassRefPtr IDBDatabaseBackendImpl::createObject void IDBDatabaseBackendImpl::createObjectStoreInternal(ScriptExecutionContext*, PassRefPtr database, PassRefPtr objectStore, PassRefPtr transaction) { - SQLiteStatement insert(database->sqliteDatabase(), "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement, databaseId) VALUES (?, ?, ?, ?)"); - if (insert.prepare() != SQLResultOk) { - transaction->abort(); - return; - } - insert.bindText(1, objectStore->name()); - insert.bindText(2, objectStore->keyPath()); - insert.bindInt(3, static_cast(objectStore->autoIncrement())); - insert.bindInt64(4, database->id()); - if (insert.step() != SQLResultDone) { + int64_t objectStoreId; + + if (!database->m_backingStore->createObjectStore(objectStore->name(), objectStore->keyPath(), objectStore->autoIncrement(), database->id(), objectStoreId)) { transaction->abort(); return; } - int64_t id = database->sqliteDatabase().lastInsertRowID(); - objectStore->setId(id); + + objectStore->setId(objectStoreId); transaction->didCompleteTaskEvents(); } @@ -172,16 +139,6 @@ PassRefPtr IDBDatabaseBackendImpl::objectStore(c return m_objectStores.get(name); } -static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id) -{ - SQLiteStatement deleteQuery(db, sql); - bool ok = deleteQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. - deleteQuery.bindInt64(1, id); - ok = deleteQuery.step() == SQLResultDone; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. -} - void IDBDatabaseBackendImpl::deleteObjectStore(const String& name, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec) { RefPtr objectStore = m_objectStores.get(name); @@ -201,19 +158,31 @@ void IDBDatabaseBackendImpl::deleteObjectStore(const String& name, IDBTransactio void IDBDatabaseBackendImpl::deleteObjectStoreInternal(ScriptExecutionContext*, PassRefPtr database, PassRefPtr objectStore, PassRefPtr transaction) { - doDelete(database->sqliteDatabase(), "DELETE FROM ObjectStores WHERE id = ?", objectStore->id()); - doDelete(database->sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStore->id()); - doDelete(database->sqliteDatabase(), "DELETE FROM IndexData WHERE indexId IN (SELECT id FROM Indexes WHERE objectStoreId = ?)", objectStore->id()); - doDelete(database->sqliteDatabase(), "DELETE FROM Indexes WHERE objectStoreId = ?", objectStore->id()); - + database->m_backingStore->deleteObjectStore(objectStore->id()); transaction->didCompleteTaskEvents(); } -void IDBDatabaseBackendImpl::setVersion(const String& version, PassRefPtr prpCallbacks, ExceptionCode& ec) +void IDBDatabaseBackendImpl::setVersion(const String& version, PassRefPtr prpCallbacks, PassRefPtr prpDatabaseCallbacks, ExceptionCode& ec) { - RefPtr database = this; RefPtr callbacks = prpCallbacks; + RefPtr databaseCallbacks = prpDatabaseCallbacks; + if (!m_databaseCallbacksSet.contains(databaseCallbacks)) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ABORT_ERR, "Connection was closed before set version transaction was created")); + return; + } + for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) { + if (*it != databaseCallbacks) + (*it)->onVersionChange(version); + } + if (m_databaseCallbacksSet.size() > 1) { + callbacks->onBlocked(); + RefPtr pendingSetVersionCall = PendingSetVersionCall::create(version, callbacks, databaseCallbacks); + m_pendingSetVersionCalls.append(pendingSetVersionCall); + return; + } + RefPtr objectStoreNames = DOMStringList::create(); + RefPtr database = this; RefPtr transaction = IDBTransactionBackendImpl::create(objectStoreNames.get(), IDBTransaction::VERSION_CHANGE, this); if (!transaction->scheduleTask(createCallbackTask(&IDBDatabaseBackendImpl::setVersionInternal, database, version, callbacks, transaction), createCallbackTask(&IDBDatabaseBackendImpl::resetVersion, database, m_version))) { @@ -225,7 +194,7 @@ void IDBDatabaseBackendImpl::setVersionInternal(ScriptExecutionContext*, PassRef { int64_t databaseId = database->id(); database->m_version = version; - if (!setMetaData(database->m_sqliteDatabase->db(), database->m_name, database->m_version, databaseId)) { + if (!database->m_backingStore->setIDBDatabaseMetaData(database->m_name, database->m_version, databaseId, databaseId == InvalidId)) { // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors. callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage.")); transaction->abort(); @@ -247,29 +216,43 @@ PassRefPtr IDBDatabaseBackendImpl::transaction(D return IDBTransactionBackendImpl::create(objectStoreNames, mode, this); } -void IDBDatabaseBackendImpl::close() +void IDBDatabaseBackendImpl::open(PassRefPtr callbacks) { - // FIXME: Implement. + m_databaseCallbacksSet.add(RefPtr(callbacks)); } -void IDBDatabaseBackendImpl::loadObjectStores() +void IDBDatabaseBackendImpl::close(PassRefPtr prpCallbacks) { - SQLiteStatement objectStoresQuery(sqliteDatabase(), "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores WHERE databaseId = ?"); - bool ok = objectStoresQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - - objectStoresQuery.bindInt64(1, m_id); - - while (objectStoresQuery.step() == SQLResultRow) { - int64_t id = objectStoresQuery.getColumnInt64(0); - String name = objectStoresQuery.getColumnText(1); - String keyPath = objectStoresQuery.getColumnText(2); - bool autoIncrement = !!objectStoresQuery.getColumnInt(3); + RefPtr callbacks = prpCallbacks; + ASSERT(m_databaseCallbacksSet.contains(callbacks)); + m_databaseCallbacksSet.remove(callbacks); + if (m_databaseCallbacksSet.size() > 1) + return; - m_objectStores.set(name, IDBObjectStoreBackendImpl::create(m_sqliteDatabase.get(), id, name, keyPath, autoIncrement)); + while (!m_pendingSetVersionCalls.isEmpty()) { + ExceptionCode ec = 0; + RefPtr pendingSetVersionCall = m_pendingSetVersionCalls.takeFirst(); + setVersion(pendingSetVersionCall->version(), pendingSetVersionCall->callbacks(), pendingSetVersionCall->databaseCallbacks(), ec); + ASSERT(!ec); } } +void IDBDatabaseBackendImpl::loadObjectStores() +{ + Vector ids; + Vector names; + Vector keyPaths; + Vector autoIncrementFlags; + m_backingStore->getObjectStores(m_id, ids, names, keyPaths, autoIncrementFlags); + + ASSERT(names.size() == ids.size()); + ASSERT(keyPaths.size() == ids.size()); + ASSERT(autoIncrementFlags.size() == ids.size()); + + for (size_t i = 0; i < ids.size(); i++) + m_objectStores.set(names[i], IDBObjectStoreBackendImpl::create(m_backingStore.get(), ids[i], names[i], keyPaths[i], autoIncrementFlags[i])); +} + void IDBDatabaseBackendImpl::removeObjectStoreFromMap(ScriptExecutionContext*, PassRefPtr database, PassRefPtr objectStore) { ASSERT(database->m_objectStores.contains(objectStore->name())); diff --git a/Source/WebCore/storage/IDBDatabaseBackendImpl.h b/Source/WebCore/storage/IDBDatabaseBackendImpl.h index 8942968..f779125 100644 --- a/Source/WebCore/storage/IDBDatabaseBackendImpl.h +++ b/Source/WebCore/storage/IDBDatabaseBackendImpl.h @@ -28,31 +28,33 @@ #include "IDBCallbacks.h" #include "IDBDatabase.h" +#include #include -#include +#include #if ENABLE(INDEXED_DATABASE) namespace WebCore { +class IDBBackingStore; +class IDBDatabase; class IDBFactoryBackendImpl; class IDBObjectStoreBackendImpl; -class IDBSQLiteDatabase; class IDBTransactionCoordinator; -class SQLiteDatabase; class IDBDatabaseBackendImpl : public IDBDatabaseBackendInterface { public: - static PassRefPtr create(const String& name, IDBSQLiteDatabase* database, IDBTransactionCoordinator* coordinator, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier) + static PassRefPtr create(const String& name, IDBBackingStore* database, IDBTransactionCoordinator* coordinator, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier) { return adoptRef(new IDBDatabaseBackendImpl(name, database, coordinator, factory, uniqueIdentifier)); } virtual ~IDBDatabaseBackendImpl(); - SQLiteDatabase& sqliteDatabase() const; + PassRefPtr backingStore() const; static const int64_t InvalidId = 0; int64_t id() const { return m_id; } + void open(PassRefPtr); virtual String name() const { return m_name; } virtual String version() const { return m_version; } @@ -60,15 +62,15 @@ public: virtual PassRefPtr createObjectStore(const String& name, const String& keyPath, bool autoIncrement, IDBTransactionBackendInterface*, ExceptionCode&); virtual void deleteObjectStore(const String& name, IDBTransactionBackendInterface*, ExceptionCode&); - virtual void setVersion(const String& version, PassRefPtr, ExceptionCode&); + virtual void setVersion(const String& version, PassRefPtr, PassRefPtr, ExceptionCode&); virtual PassRefPtr transaction(DOMStringList* objectStoreNames, unsigned short mode, ExceptionCode&); - virtual void close(); + virtual void close(PassRefPtr); PassRefPtr objectStore(const String& name); IDBTransactionCoordinator* transactionCoordinator() const { return m_transactionCoordinator.get(); } private: - IDBDatabaseBackendImpl(const String& name, IDBSQLiteDatabase* database, IDBTransactionCoordinator*, IDBFactoryBackendImpl*, const String& uniqueIdentifier); + IDBDatabaseBackendImpl(const String& name, IDBBackingStore* database, IDBTransactionCoordinator*, IDBFactoryBackendImpl*, const String& uniqueIdentifier); void loadObjectStores(); @@ -81,7 +83,7 @@ private: static void addObjectStoreToMap(ScriptExecutionContext*, PassRefPtr, PassRefPtr); static void resetVersion(ScriptExecutionContext*, PassRefPtr, const String& version); - RefPtr m_sqliteDatabase; + RefPtr m_backingStore; int64 m_id; String m_name; String m_version; @@ -94,6 +96,12 @@ private: ObjectStoreMap m_objectStores; RefPtr m_transactionCoordinator; + + class PendingSetVersionCall; + Deque > m_pendingSetVersionCalls; + + typedef ListHashSet > DatabaseCallbacksSet; + DatabaseCallbacksSet m_databaseCallbacksSet; }; } // namespace WebCore diff --git a/Source/WebCore/storage/IDBDatabaseBackendInterface.h b/Source/WebCore/storage/IDBDatabaseBackendInterface.h index 9cc7230..ad6fdc7 100644 --- a/Source/WebCore/storage/IDBDatabaseBackendInterface.h +++ b/Source/WebCore/storage/IDBDatabaseBackendInterface.h @@ -38,9 +38,9 @@ namespace WebCore { class DOMStringList; class Frame; class IDBCallbacks; +class IDBDatabaseCallbacks; class IDBObjectStoreBackendInterface; class IDBTransactionBackendInterface; -class IDBTransactionCallbacks; // This class is shared by IDBDatabase (async) and IDBDatabaseSync (sync). // This is implemented by IDBDatabaseBackendImpl and optionally others (in order to proxy @@ -56,9 +56,11 @@ public: virtual PassRefPtr createObjectStore(const String& name, const String& keyPath, bool autoIncrement, IDBTransactionBackendInterface*, ExceptionCode&) = 0; virtual void deleteObjectStore(const String& name, IDBTransactionBackendInterface*, ExceptionCode&) = 0; - virtual void setVersion(const String& version, PassRefPtr, ExceptionCode&) = 0; + virtual void setVersion(const String& version, PassRefPtr, PassRefPtr, ExceptionCode&) = 0; virtual PassRefPtr transaction(DOMStringList* storeNames, unsigned short mode, ExceptionCode&) = 0; - virtual void close() = 0; + virtual void close(PassRefPtr) = 0; + + virtual void open(PassRefPtr) = 0; }; } // namespace WebCore diff --git a/Source/WebCore/storage/IDBDatabaseCallbacks.h b/Source/WebCore/storage/IDBDatabaseCallbacks.h new file mode 100644 index 0000000..b3f244f --- /dev/null +++ b/Source/WebCore/storage/IDBDatabaseCallbacks.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBDatabaseCallbacks_h +#define IDBDatabaseCallbacks_h + +#if ENABLE(INDEXED_DATABASE) + +#include "PlatformString.h" +#include + +namespace WebCore { + +class IDBDatabaseCallbacks : public RefCounted { +public: + virtual ~IDBDatabaseCallbacks() { } + + virtual void onVersionChange(const String& version) = 0; +}; + +} // namespace WebCore + +#endif + +#endif // IDBDatabaseCallbacks_h diff --git a/Source/WebCore/storage/IDBDatabaseException.h b/Source/WebCore/storage/IDBDatabaseException.h index 174fe5b..21991ee 100644 --- a/Source/WebCore/storage/IDBDatabaseException.h +++ b/Source/WebCore/storage/IDBDatabaseException.h @@ -43,6 +43,7 @@ public: static const int IDBDatabaseExceptionMax = 1299; enum IDBDatabaseExceptionCode { + NO_ERR = IDBDatabaseExceptionOffset + 0, UNKNOWN_ERR = IDBDatabaseExceptionOffset + 1, NON_TRANSIENT_ERR = IDBDatabaseExceptionOffset + 2, NOT_FOUND_ERR = IDBDatabaseExceptionOffset + 3, @@ -54,7 +55,8 @@ public: TRANSIENT_ERR = IDBDatabaseExceptionOffset + 9, TIMEOUT_ERR = IDBDatabaseExceptionOffset + 10, DEADLOCK_ERR = IDBDatabaseExceptionOffset + 11, - READ_ONLY_ERR = IDBDatabaseExceptionOffset + 12 + READ_ONLY_ERR = IDBDatabaseExceptionOffset + 12, + ABORT_ERR = IDBDatabaseExceptionOffset + 13 }; static int ErrorCodeToExceptionCode(int errorCode) diff --git a/Source/WebCore/storage/IDBDatabaseException.idl b/Source/WebCore/storage/IDBDatabaseException.idl index 9027e05..d603057 100644 --- a/Source/WebCore/storage/IDBDatabaseException.idl +++ b/Source/WebCore/storage/IDBDatabaseException.idl @@ -39,6 +39,7 @@ module storage { [DontEnum] DOMString toString(); #endif + const unsigned short NO_ERR = 0; const unsigned short UNKNOWN_ERR = 1; const unsigned short NON_TRANSIENT_ERR = 2; const unsigned short NOT_FOUND_ERR = 3; @@ -51,6 +52,7 @@ module storage { const unsigned short TIMEOUT_ERR = 10; const unsigned short DEADLOCK_ERR = 11; const unsigned short READ_ONLY_ERR = 12; + const unsigned short ABORT_ERR = 13; }; } diff --git a/Source/WebCore/storage/IDBErrorEvent.cpp b/Source/WebCore/storage/IDBErrorEvent.cpp deleted file mode 100644 index e576fa8..0000000 --- a/Source/WebCore/storage/IDBErrorEvent.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBErrorEvent.h" - -#if ENABLE(INDEXED_DATABASE) - -#include "EventNames.h" -#include "IDBAny.h" -#include "IDBDatabaseError.h" - -namespace WebCore { - -PassRefPtr IDBErrorEvent::create(PassRefPtr source, const IDBDatabaseError& error) -{ - return adoptRef(new IDBErrorEvent(source, error)); -} - -IDBErrorEvent::IDBErrorEvent(PassRefPtr source, const IDBDatabaseError& error) - : IDBEvent(eventNames().errorEvent, source, true) - , m_code(error.code()) - , m_message(error.message()) -{ -} - -IDBErrorEvent::~IDBErrorEvent() -{ -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/storage/IDBErrorEvent.h b/Source/WebCore/storage/IDBErrorEvent.h deleted file mode 100644 index 648da8b..0000000 --- a/Source/WebCore/storage/IDBErrorEvent.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBErrorEvent_h -#define IDBErrorEvent_h - -#if ENABLE(INDEXED_DATABASE) - -#include "IDBEvent.h" -#include "PlatformString.h" -#include -#include - -namespace WebCore { - -class IDBAny; -class IDBDatabaseError; - -class IDBErrorEvent : public IDBEvent { -public: - static PassRefPtr create(PassRefPtr source, const IDBDatabaseError&); - // FIXME: Need to allow creation of these events from JS. - virtual ~IDBErrorEvent(); - - unsigned short code() const { return m_code; } - String message() { return m_message; } - - virtual bool isIDBErrorEvent() const { return true; } - -private: - IDBErrorEvent(PassRefPtr source, const IDBDatabaseError&); - - unsigned short m_code; - String m_message; -}; - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) - -#endif // IDBEvent_h diff --git a/Source/WebCore/storage/IDBErrorEvent.idl b/Source/WebCore/storage/IDBErrorEvent.idl deleted file mode 100644 index 5c58f6f..0000000 --- a/Source/WebCore/storage/IDBErrorEvent.idl +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -module storage { - - interface [ - Conditional=INDEXED_DATABASE - ] IDBErrorEvent : IDBEvent { - readonly attribute unsigned short code; - readonly attribute DOMString message; - }; -} diff --git a/Source/WebCore/storage/IDBEvent.cpp b/Source/WebCore/storage/IDBEvent.cpp deleted file mode 100644 index a7f3db1..0000000 --- a/Source/WebCore/storage/IDBEvent.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBEvent.h" - -#if ENABLE(INDEXED_DATABASE) - -#include "IDBAny.h" - -namespace WebCore { - -IDBEvent::IDBEvent(const AtomicString& type, PassRefPtr source, bool canBubble) - : Event(type, canBubble, true) - , m_source(source) -{ -} - -IDBEvent::~IDBEvent() -{ -} - -PassRefPtr IDBEvent::source() -{ - return m_source; -} - -bool IDBEvent::dispatch(Vector >& eventTargets) -{ - size_t size = eventTargets.size(); - ASSERT(size); - - setEventPhase(Event::CAPTURING_PHASE); - for (size_t i = size - 1; i; --i) { // Don't do the first element. - setCurrentTarget(eventTargets[i].get()); - eventTargets[i]->fireEventListeners(this); - if (propagationStopped()) - goto doneDispatching; - } - - setEventPhase(Event::AT_TARGET); - setCurrentTarget(eventTargets[0].get()); - eventTargets[0]->fireEventListeners(this); - if (propagationStopped() || !bubbles() || cancelBubble()) - goto doneDispatching; - - setEventPhase(Event::BUBBLING_PHASE); - for (size_t i = 1; i < size; ++i) { // Don't do the first element. - setCurrentTarget(eventTargets[i].get()); - eventTargets[i]->fireEventListeners(this); - if (propagationStopped() || cancelBubble()) - goto doneDispatching; - } - - // FIXME: "...However, we also wanted to integrate the window.onerror feature in - // HTML5. So after we've fired an "error" event, if .preventDefault() was - // never called on the event, we fire an error event on the window (can't - // remember if this happens before or after we abort the transaction). - // This is a separate event, which for example means that even if you - // attach a capturing "error" handler on window, you won't see any events - // unless an error really went unhandled. And you also can't call - // .preventDefault on the error event fired on the window in order to - // prevent the transaction from being aborted. It's purely there for - // error reporting and distinctly different from the event propagating to - // the window. - // - // This is similar to how "error" events are handled in workers. - // - // (I think that so far webkit hasn't implemented the window.onerror - // feature yet, so you probably don't want to fire the separate error - // event on the window until that has been implemented)." - -doneDispatching: - setCurrentTarget(0); - setEventPhase(0); - return !defaultPrevented(); -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/storage/IDBEvent.h b/Source/WebCore/storage/IDBEvent.h deleted file mode 100644 index d28885b..0000000 --- a/Source/WebCore/storage/IDBEvent.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBEvent_h -#define IDBEvent_h - -#if ENABLE(INDEXED_DATABASE) - -#include "Event.h" -#include "EventTarget.h" -#include -#include -#include - -namespace WebCore { - -class IDBAny; - -class IDBEvent : public Event { -public: - virtual ~IDBEvent(); - - PassRefPtr source(); - bool dispatch(Vector >&); // The target first and then its ancestors in order of how the event bubbles. - -protected: - IDBEvent(const AtomicString& type, PassRefPtr source, bool canBubble); - -private: - RefPtr m_source; -}; - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) - -#endif // IDBEvent_h diff --git a/Source/WebCore/storage/IDBEvent.idl b/Source/WebCore/storage/IDBEvent.idl deleted file mode 100644 index 4dd552e..0000000 --- a/Source/WebCore/storage/IDBEvent.idl +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -module storage { - - interface [ - Conditional=INDEXED_DATABASE - ] IDBEvent : Event { - readonly attribute IDBAny source; - }; -} diff --git a/Source/WebCore/storage/IDBEventDispatcher.cpp b/Source/WebCore/storage/IDBEventDispatcher.cpp new file mode 100644 index 0000000..7263467 --- /dev/null +++ b/Source/WebCore/storage/IDBEventDispatcher.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBEventDispatcher.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "Event.h" +#include "EventTarget.h" + +namespace WebCore { + +bool IDBEventDispatcher::dispatch(Event* event, Vector >& eventTargets) +{ + size_t size = eventTargets.size(); + ASSERT(size); + + event->setEventPhase(Event::CAPTURING_PHASE); + for (size_t i = size - 1; i; --i) { // Don't do the first element. + event->setCurrentTarget(eventTargets[i].get()); + eventTargets[i]->fireEventListeners(event); + if (event->propagationStopped()) + goto doneDispatching; + } + + event->setEventPhase(Event::AT_TARGET); + event->setCurrentTarget(eventTargets[0].get()); + eventTargets[0]->fireEventListeners(event); + if (event->propagationStopped() || !event->bubbles() || event->cancelBubble()) + goto doneDispatching; + + event->setEventPhase(Event::BUBBLING_PHASE); + for (size_t i = 1; i < size; ++i) { // Don't do the first element. + event->setCurrentTarget(eventTargets[i].get()); + eventTargets[i]->fireEventListeners(event); + if (event->propagationStopped() || event->cancelBubble()) + goto doneDispatching; + } + + // FIXME: "...However, we also wanted to integrate the window.onerror feature in + // HTML5. So after we've fired an "error" event, if .preventDefault() was + // never called on the event, we fire an error event on the window (can't + // remember if this happens before or after we abort the transaction). + // This is a separate event, which for example means that even if you + // attach a capturing "error" handler on window, you won't see any events + // unless an error really went unhandled. And you also can't call + // .preventDefault on the error event fired on the window in order to + // prevent the transaction from being aborted. It's purely there for + // error reporting and distinctly different from the event propagating to + // the window. + // + // This is similar to how "error" events are handled in workers. + // + // (I think that so far webkit hasn't implemented the window.onerror + // feature yet, so you probably don't want to fire the separate error + // event on the window until that has been implemented)." -- Jonas Sicking + +doneDispatching: + event->setCurrentTarget(0); + event->setEventPhase(0); + return !event->defaultPrevented(); +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/storage/IDBEventDispatcher.h b/Source/WebCore/storage/IDBEventDispatcher.h new file mode 100644 index 0000000..00bf154 --- /dev/null +++ b/Source/WebCore/storage/IDBEventDispatcher.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBEventDispatcher_h +#define IDBEventDispatcher_h + +#if ENABLE(INDEXED_DATABASE) + +#include +#include + +namespace WebCore { + +class Event; +class EventTarget; + +class IDBEventDispatcher { +public: + static bool dispatch(Event*, Vector >&); // The target first and then its ancestors in order of how the event bubbles. + +private: + IDBEventDispatcher(); +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBEventDispatcher_h diff --git a/Source/WebCore/storage/IDBFactoryBackendImpl.cpp b/Source/WebCore/storage/IDBFactoryBackendImpl.cpp index 0e883cf..9127455 100644 --- a/Source/WebCore/storage/IDBFactoryBackendImpl.cpp +++ b/Source/WebCore/storage/IDBFactoryBackendImpl.cpp @@ -30,13 +30,10 @@ #include "IDBFactoryBackendImpl.h" #include "DOMStringList.h" -#include "FileSystem.h" +#include "IDBBackingStore.h" #include "IDBDatabaseBackendImpl.h" #include "IDBDatabaseException.h" -#include "IDBSQLiteDatabase.h" #include "IDBTransactionCoordinator.h" -#include "SQLiteStatement.h" -#include "SQLiteTransaction.h" #include "SecurityOrigin.h" #include #include @@ -45,11 +42,11 @@ namespace WebCore { -IDBFactoryBackendImpl::IDBFactoryBackendImpl() +IDBFactoryBackendImpl::IDBFactoryBackendImpl() : m_transactionCoordinator(IDBTransactionCoordinator::create()) { } - + IDBFactoryBackendImpl::~IDBFactoryBackendImpl() { } @@ -60,151 +57,16 @@ void IDBFactoryBackendImpl::removeIDBDatabaseBackend(const String& uniqueIdentif m_databaseBackendMap.remove(uniqueIdentifier); } -void IDBFactoryBackendImpl::removeSQLiteDatabase(const String& uniqueIdentifier) -{ - ASSERT(m_sqliteDatabaseMap.contains(uniqueIdentifier)); - m_sqliteDatabaseMap.remove(uniqueIdentifier); -} - -static PassRefPtr openSQLiteDatabase(SecurityOrigin* securityOrigin, const String& pathBase, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl* factory) -{ - String path = ":memory:"; - if (!pathBase.isEmpty()) { - if (!makeAllDirectories(pathBase)) { - // FIXME: Is there any other thing we could possibly do to recover at this point? If so, do it rather than just erroring out. - LOG_ERROR("Unabled to create LocalStorage database path %s", pathBase.utf8().data()); - return 0; - } - - path = pathByAppendingComponent(pathBase, securityOrigin->databaseIdentifier() + ".indexeddb"); - } - - RefPtr sqliteDatabase = IDBSQLiteDatabase::create(fileIdentifier, factory); - if (!sqliteDatabase->db().open(path)) { - // FIXME: Is there any other thing we could possibly do to recover at this point? If so, do it rather than just erroring out. - LOG_ERROR("Failed to open database file %s for IndexedDB", path.utf8().data()); - return 0; - } - - // FIXME: Error checking? - sqliteDatabase->db().setMaximumSize(maximumSize); - sqliteDatabase->db().turnOnIncrementalAutoVacuum(); - - return sqliteDatabase.release(); -} - -static bool runCommands(SQLiteDatabase& sqliteDatabase, const char** commands, size_t numberOfCommands) -{ - SQLiteTransaction transaction(sqliteDatabase, false); - transaction.begin(); - for (size_t i = 0; i < numberOfCommands; ++i) { - if (!sqliteDatabase.executeCommand(commands[i])) { - LOG_ERROR("Failed to run the following command for IndexedDB: %s", commands[i]); - return false; - } - } - transaction.commit(); - return true; -} - -static bool createTables(SQLiteDatabase& sqliteDatabase) -{ - if (sqliteDatabase.tableExists("Databases")) - return true; - static const char* commands[] = { - "CREATE TABLE Databases (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL)", - "CREATE UNIQUE INDEX Databases_name ON Databases(name)", - - "CREATE TABLE ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL, keyPath TEXT, doAutoIncrement INTEGER NOT NULL, databaseId INTEGER NOT NULL REFERENCES Databases(id))", - "CREATE UNIQUE INDEX ObjectStores_composit ON ObjectStores(databaseId, name)", - - "CREATE TABLE Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT, isUnique INTEGER NOT NULL)", - "CREATE UNIQUE INDEX Indexes_composit ON Indexes(objectStoreId, name)", - - "CREATE TABLE ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, value TEXT NOT NULL)", - "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)", - - "CREATE TABLE IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))", - "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)", - "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDataId)", - "CREATE INDEX IndexData_indexId ON IndexData(indexId)", - }; - - return runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0])); -} - -static bool createMetaDataTable(SQLiteDatabase& sqliteDatabase) +void IDBFactoryBackendImpl::addIDBBackingStore(const String& uniqueIdentifier, IDBBackingStore* backingStore) { - static const char* commands[] = { - "CREATE TABLE MetaData (name TEXT PRIMARY KEY, value NONE)", - "INSERT INTO MetaData VALUES ('version', 1)", - }; - - return runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0])); + ASSERT(!m_backingStoreMap.contains(uniqueIdentifier)); + m_backingStoreMap.set(uniqueIdentifier, backingStore); } -static bool getDatabaseVersion(SQLiteDatabase& sqliteDatabase, int* databaseVersion) +void IDBFactoryBackendImpl::removeIDBBackingStore(const String& uniqueIdentifier) { - SQLiteStatement query(sqliteDatabase, "SELECT value FROM MetaData WHERE name = 'version'"); - if (query.prepare() != SQLResultOk || query.step() != SQLResultRow) - return false; - - *databaseVersion = query.getColumnInt(0); - return query.finalize() == SQLResultOk; -} - -static bool migrateDatabase(SQLiteDatabase& sqliteDatabase) -{ - if (!sqliteDatabase.tableExists("MetaData")) { - if (!createMetaDataTable(sqliteDatabase)) - return false; - } - - int databaseVersion; - if (!getDatabaseVersion(sqliteDatabase, &databaseVersion)) - return false; - - if (databaseVersion == 1) { - static const char* commands[] = { - "DROP TABLE IF EXISTS ObjectStoreData2", - "CREATE TABLE ObjectStoreData2 (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate REAL, keyNumber REAL, value TEXT NOT NULL)", - "INSERT INTO ObjectStoreData2 SELECT * FROM ObjectStoreData", - "DROP TABLE ObjectStoreData", // This depends on SQLite not enforcing referential consistency. - "ALTER TABLE ObjectStoreData2 RENAME TO ObjectStoreData", - "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)", - "DROP TABLE IF EXISTS IndexData2", // This depends on SQLite not enforcing referential consistency. - "CREATE TABLE IndexData2 (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate REAL, keyNumber REAL, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))", - "INSERT INTO IndexData2 SELECT * FROM IndexData", - "DROP TABLE IndexData", - "ALTER TABLE IndexData2 RENAME TO IndexData", - "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)", - "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDataId)", - "CREATE INDEX IndexData_indexId ON IndexData(indexId)", - "UPDATE MetaData SET value = 2 WHERE name = 'version'", - }; - - if (!runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0]))) - return false; - - databaseVersion = 2; - } - - if (databaseVersion == 2) { - // We need to make the ObjectStoreData.value be a BLOB instead of TEXT. - static const char* commands[] = { - "DROP TABLE IF EXISTS ObjectStoreData", // This drops associated indices. - "CREATE TABLE ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate REAL, keyNumber REAL, value BLOB NOT NULL)", - "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)", - "UPDATE MetaData SET value = 3 WHERE name = 'version'", - }; - - if (!runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0]))) - return false; - - databaseVersion = 3; - } - - return true; + ASSERT(m_backingStoreMap.contains(uniqueIdentifier)); + m_backingStoreMap.remove(uniqueIdentifier); } void IDBFactoryBackendImpl::open(const String& name, PassRefPtr callbacks, PassRefPtr securityOrigin, Frame*, const String& dataDir, int64_t maximumSize) @@ -219,22 +81,19 @@ void IDBFactoryBackendImpl::open(const String& name, PassRefPtr ca // FIXME: Everything from now on should be done on another thread. - RefPtr sqliteDatabase; - SQLiteDatabaseMap::iterator it2 = m_sqliteDatabaseMap.find(fileIdentifier); - if (it2 != m_sqliteDatabaseMap.end()) - sqliteDatabase = it2->second; + RefPtr backingStore; + IDBBackingStoreMap::iterator it2 = m_backingStoreMap.find(fileIdentifier); + if (it2 != m_backingStoreMap.end()) + backingStore = it2->second; else { - sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), dataDir, maximumSize, fileIdentifier, this); - - if (!sqliteDatabase || !createTables(sqliteDatabase->db()) || !migrateDatabase(sqliteDatabase->db())) { + backingStore = IDBBackingStore::open(securityOrigin.get(), dataDir, maximumSize, fileIdentifier, this); + if (!backingStore) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error.")); - m_sqliteDatabaseMap.set(fileIdentifier, 0); return; } - m_sqliteDatabaseMap.set(fileIdentifier, sqliteDatabase.get()); } - RefPtr databaseBackend = IDBDatabaseBackendImpl::create(name, sqliteDatabase.get(), m_transactionCoordinator.get(), this, uniqueIdentifier); + RefPtr databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), m_transactionCoordinator.get(), this, uniqueIdentifier); callbacks->onSuccess(databaseBackend.get()); m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get()); } diff --git a/Source/WebCore/storage/IDBFactoryBackendImpl.h b/Source/WebCore/storage/IDBFactoryBackendImpl.h index dcaf848..071bcf8 100644 --- a/Source/WebCore/storage/IDBFactoryBackendImpl.h +++ b/Source/WebCore/storage/IDBFactoryBackendImpl.h @@ -38,8 +38,8 @@ namespace WebCore { class DOMStringList; +class IDBBackingStore; class IDBDatabaseBackendImpl; -class IDBSQLiteDatabase; class IDBTransactionCoordinator; class IDBFactoryBackendImpl : public IDBFactoryBackendInterface { @@ -52,7 +52,8 @@ public: // Notifications from weak pointers. void removeIDBDatabaseBackend(const String& uniqueIdentifier); - void removeSQLiteDatabase(const String& uniqueIdentifier); + void addIDBBackingStore(const String& uniqueIdentifier, IDBBackingStore*); + void removeIDBBackingStore(const String& uniqueIdentifier); virtual void open(const String& name, PassRefPtr, PassRefPtr, Frame*, const String& dataDir, int64_t maximumSize); @@ -62,8 +63,8 @@ private: typedef HashMap IDBDatabaseBackendMap; IDBDatabaseBackendMap m_databaseBackendMap; - typedef HashMap SQLiteDatabaseMap; - SQLiteDatabaseMap m_sqliteDatabaseMap; + typedef HashMap IDBBackingStoreMap; + IDBBackingStoreMap m_backingStoreMap; RefPtr m_transactionCoordinator; @@ -76,4 +77,3 @@ private: #endif #endif // IDBFactoryBackendImpl_h - diff --git a/Source/WebCore/storage/IDBIndex.cpp b/Source/WebCore/storage/IDBIndex.cpp index 615767b..5f2ecf2 100644 --- a/Source/WebCore/storage/IDBIndex.cpp +++ b/Source/WebCore/storage/IDBIndex.cpp @@ -33,6 +33,7 @@ #include "IDBIndexBackendInterface.h" #include "IDBKey.h" #include "IDBKeyRange.h" +#include "IDBObjectStore.h" #include "IDBRequest.h" #include "IDBTransaction.h" @@ -40,11 +41,13 @@ namespace WebCore { static const unsigned short defaultDirection = IDBCursor::NEXT; -IDBIndex::IDBIndex(PassRefPtr backend, IDBTransaction* transaction) +IDBIndex::IDBIndex(PassRefPtr backend, IDBObjectStore* objectStore, IDBTransaction* transaction) : m_backend(backend) + , m_objectStore(objectStore) , m_transaction(transaction) { ASSERT(m_backend); + ASSERT(m_objectStore); ASSERT(m_transaction); } @@ -61,9 +64,12 @@ PassRefPtr IDBIndex::openCursor(ScriptExecutionContext* context, Pas } RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); + request->setCursorType(IDBCursorBackendInterface::IndexCursor); m_backend->openCursor(keyRange, direction, request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; + } return request; } @@ -76,9 +82,12 @@ PassRefPtr IDBIndex::openKeyCursor(ScriptExecutionContext* context, } RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); + request->setCursorType(IDBCursorBackendInterface::IndexKeyCursor); m_backend->openKeyCursor(keyRange, direction, request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; + } return request; } @@ -86,8 +95,10 @@ PassRefPtr IDBIndex::get(ScriptExecutionContext* context, PassRefPtr { RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); m_backend->get(key, request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; + } return request; } @@ -95,8 +106,10 @@ PassRefPtr IDBIndex::getKey(ScriptExecutionContext* context, PassRef { RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); m_backend->getKey(key, request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; + } return request; } diff --git a/Source/WebCore/storage/IDBIndex.h b/Source/WebCore/storage/IDBIndex.h index 10b46f1..2af1805 100644 --- a/Source/WebCore/storage/IDBIndex.h +++ b/Source/WebCore/storage/IDBIndex.h @@ -37,17 +37,19 @@ namespace WebCore { +class IDBObjectStore; + class IDBIndex : public RefCounted { public: - static PassRefPtr create(PassRefPtr backend, IDBTransaction* transaction) + static PassRefPtr create(PassRefPtr backend, IDBObjectStore* objectStore, IDBTransaction* transaction) { - return adoptRef(new IDBIndex(backend, transaction)); + return adoptRef(new IDBIndex(backend, objectStore, transaction)); } ~IDBIndex(); // Implement the IDL String name() const { return m_backend->name(); } - String storeName() const { return m_backend->storeName(); } + IDBObjectStore* objectStore() const { return m_objectStore.get(); } String keyPath() const { return m_backend->keyPath(); } bool unique() const { return m_backend->unique(); } @@ -64,9 +66,10 @@ public: PassRefPtr getKey(ScriptExecutionContext*, PassRefPtr, ExceptionCode&); private: - IDBIndex(PassRefPtr, IDBTransaction*); + IDBIndex(PassRefPtr, IDBObjectStore*, IDBTransaction*); RefPtr m_backend; + RefPtr m_objectStore; RefPtr m_transaction; }; diff --git a/Source/WebCore/storage/IDBIndex.idl b/Source/WebCore/storage/IDBIndex.idl index 13089cc..6db50e1 100644 --- a/Source/WebCore/storage/IDBIndex.idl +++ b/Source/WebCore/storage/IDBIndex.idl @@ -29,7 +29,7 @@ module storage { Conditional=INDEXED_DATABASE ] IDBIndex { readonly attribute DOMString name; - readonly attribute DOMString storeName; + readonly attribute IDBObjectStore objectStore; readonly attribute DOMString keyPath; readonly attribute boolean unique; diff --git a/Source/WebCore/storage/IDBIndexBackendImpl.cpp b/Source/WebCore/storage/IDBIndexBackendImpl.cpp index 6eba189..62e5364 100644 --- a/Source/WebCore/storage/IDBIndexBackendImpl.cpp +++ b/Source/WebCore/storage/IDBIndexBackendImpl.cpp @@ -29,6 +29,7 @@ #if ENABLE(INDEXED_DATABASE) #include "CrossThreadTask.h" +#include "IDBBackingStore.h" #include "IDBCallbacks.h" #include "IDBCursorBackendImpl.h" #include "IDBDatabaseBackendImpl.h" @@ -36,14 +37,11 @@ #include "IDBKey.h" #include "IDBKeyRange.h" #include "IDBObjectStoreBackendImpl.h" -#include "IDBSQLiteDatabase.h" -#include "SQLiteDatabase.h" -#include "SQLiteStatement.h" namespace WebCore { -IDBIndexBackendImpl::IDBIndexBackendImpl(IDBSQLiteDatabase* database, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique) - : m_database(database) +IDBIndexBackendImpl::IDBIndexBackendImpl(IDBBackingStore* backingStore, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique) + : m_backingStore(backingStore) , m_id(id) , m_name(name) , m_storeName(storeName) @@ -52,8 +50,8 @@ IDBIndexBackendImpl::IDBIndexBackendImpl(IDBSQLiteDatabase* database, int64_t id { } -IDBIndexBackendImpl::IDBIndexBackendImpl(IDBSQLiteDatabase* database, const String& name, const String& storeName, const String& keyPath, bool unique) - : m_database(database) +IDBIndexBackendImpl::IDBIndexBackendImpl(IDBBackingStore* backingStore, const String& name, const String& storeName, const String& keyPath, bool unique) + : m_backingStore(backingStore) , m_id(InvalidId) , m_name(name) , m_storeName(storeName) @@ -66,40 +64,26 @@ IDBIndexBackendImpl::~IDBIndexBackendImpl() { } -void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr index, PassRefPtr range, unsigned short untypedDirection, bool objectCursor, PassRefPtr callbacks, PassRefPtr transaction) +void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr index, PassRefPtr range, unsigned short untypedDirection, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr callbacks, PassRefPtr transaction) { - // Several files depend on this order of selects. - String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ") - + ("ObjectStoreData.value, ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") - + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE "; - - bool lowerBound = range && range->lower(); - bool upperBound = range && range->upper(); - - if (lowerBound) - sql += range->lower()->lowerCursorWhereFragment(range->lowerWhereClauseComparisonOperator(), "IndexData."); - if (upperBound) - sql += range->upper()->upperCursorWhereFragment(range->upperWhereClauseComparisonOperator(), "IndexData."); - sql += "IndexData.indexId = ? ORDER BY "; - IDBCursor::Direction direction = static_cast(untypedDirection); - if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) - sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id"; - else - sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC"; - - OwnPtr query = adoptPtr(new SQLiteStatement(index->sqliteDatabase(), sql)); - bool ok = query->prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - - int indexColumn = 1; - if (lowerBound) - indexColumn += range->lower()->bind(*query, indexColumn); - if (upperBound) - indexColumn += range->upper()->bind(*query, indexColumn); - query->bindInt64(indexColumn, index->id()); - - if (query->step() != SQLResultRow) { + + RefPtr backingStoreCursor; + + switch (cursorType) { + case IDBCursorBackendInterface::IndexKeyCursor: + backingStoreCursor = index->m_backingStore->openIndexKeyCursor(index->id(), range.get(), direction); + break; + case IDBCursorBackendInterface::IndexCursor: + backingStoreCursor = index->m_backingStore->openIndexCursor(index->id(), range.get(), direction); + break; + case IDBCursorBackendInterface::ObjectStoreCursor: + case IDBCursorBackendInterface::InvalidCursorType: + ASSERT_NOT_REACHED(); + break; + } + + if (!backingStoreCursor) { callbacks->onSuccess(SerializedScriptValue::nullValue()); return; } @@ -108,7 +92,7 @@ void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr RefPtr objectStore = transaction->objectStore(index->m_storeName, ec); ASSERT(objectStore && !ec); - RefPtr cursor = IDBCursorBackendImpl::create(index->m_database.get(), range, direction, query.release(), objectCursor, transaction.get(), objectStore.get()); + RefPtr cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), direction, cursorType, transaction.get(), objectStore.get()); callbacks->onSuccess(cursor.release()); } @@ -118,7 +102,7 @@ void IDBIndexBackendImpl::openCursor(PassRefPtr prpKeyRange, unsign RefPtr keyRange = prpKeyRange; RefPtr callbacks = prpCallbacks; RefPtr transaction = transactionPtr; - if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, true, callbacks, transaction))) + if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexCursor, callbacks, transaction))) ec = IDBDatabaseException::NOT_ALLOWED_ERR; } @@ -128,33 +112,28 @@ void IDBIndexBackendImpl::openKeyCursor(PassRefPtr prpKeyRange, uns RefPtr keyRange = prpKeyRange; RefPtr callbacks = prpCallbacks; RefPtr transaction = transactionPtr; - if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, false, callbacks, transaction))) + if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexKeyCursor, callbacks, transaction))) ec = IDBDatabaseException::NOT_ALLOWED_ERR; } void IDBIndexBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr index, PassRefPtr key, bool getObject, PassRefPtr callbacks) { - String sql = String("SELECT ") - + (getObject ? "ObjectStoreData.value " : "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") - + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id " - + "WHERE IndexData.indexId = ? AND " + key->whereSyntax("IndexData.") - + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails. - SQLiteStatement query(index->sqliteDatabase(), sql); - bool ok = query.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - - query.bindInt64(1, index->id()); - key->bind(query, 2); - if (query.step() != SQLResultRow) { - callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index.")); - return; + // FIXME: Split getInternal into two functions, getting rid off |getObject|. + if (getObject) { + String value = index->m_backingStore->getObjectViaIndex(index->id(), *key); + if (value.isNull()) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index.")); + return; + } + callbacks->onSuccess(SerializedScriptValue::createFromWire(value)); + } else { + RefPtr keyResult = index->m_backingStore->getPrimaryKeyViaIndex(index->id(), *key); + if (!keyResult) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index.")); + return; + } + callbacks->onSuccess(keyResult.get()); } - - if (getObject) - callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(0))); - else - callbacks->onSuccess(IDBKey::fromQuery(query, 0)); - ASSERT(query.step() != SQLResultRow); } void IDBIndexBackendImpl::get(PassRefPtr prpKey, PassRefPtr prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec) @@ -175,34 +154,12 @@ void IDBIndexBackendImpl::getKey(PassRefPtr prpKey, PassRefPtrwhereSyntax(); -} - -static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key) -{ - query.bindInt64(1, id); - key->bind(query, 2); -} - bool IDBIndexBackendImpl::addingKeyAllowed(IDBKey* key) { if (!m_unique) return true; - SQLiteStatement query(sqliteDatabase(), "SELECT id FROM IndexData " + whereClause(key)); - bool ok = query.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - bindWhereClause(query, m_id, key); - bool existingValue = query.step() == SQLResultRow; - - return !existingValue; -} - -SQLiteDatabase& IDBIndexBackendImpl::sqliteDatabase() const -{ - return m_database->db(); + return !m_backingStore->keyExistsInIndex(m_id, *key); } } // namespace WebCore diff --git a/Source/WebCore/storage/IDBIndexBackendImpl.h b/Source/WebCore/storage/IDBIndexBackendImpl.h index e640b5a..e2a06b8 100644 --- a/Source/WebCore/storage/IDBIndexBackendImpl.h +++ b/Source/WebCore/storage/IDBIndexBackendImpl.h @@ -26,27 +26,27 @@ #ifndef IDBIndexBackendImpl_h #define IDBIndexBackendImpl_h -#include "IDBIndexBackendInterface.h" - #if ENABLE(INDEXED_DATABASE) +#include "IDBCursorBackendInterface.h" +#include "IDBIndexBackendInterface.h" + namespace WebCore { +class IDBBackingStore; class IDBKey; class IDBObjectStoreBackendImpl; -class IDBSQLiteDatabase; -class SQLiteDatabase; class ScriptExecutionContext; class IDBIndexBackendImpl : public IDBIndexBackendInterface { public: - static PassRefPtr create(IDBSQLiteDatabase* database, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique) + static PassRefPtr create(IDBBackingStore* backingStore, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique) { - return adoptRef(new IDBIndexBackendImpl(database, id, name, storeName, keyPath, unique)); + return adoptRef(new IDBIndexBackendImpl(backingStore, id, name, storeName, keyPath, unique)); } - static PassRefPtr create(IDBSQLiteDatabase* database, const String& name, const String& storeName, const String& keyPath, bool unique) + static PassRefPtr create(IDBBackingStore* backingStore, const String& name, const String& storeName, const String& keyPath, bool unique) { - return adoptRef(new IDBIndexBackendImpl(database, name, storeName, keyPath, unique)); + return adoptRef(new IDBIndexBackendImpl(backingStore, name, storeName, keyPath, unique)); } virtual ~IDBIndexBackendImpl(); @@ -56,6 +56,7 @@ public: return m_id; } void setId(int64_t id) { m_id = id; } + bool hasValidId() const { return m_id != InvalidId; }; bool addingKeyAllowed(IDBKey*); @@ -71,17 +72,15 @@ public: virtual void getKey(PassRefPtr, PassRefPtr, IDBTransactionBackendInterface*, ExceptionCode&); private: - IDBIndexBackendImpl(IDBSQLiteDatabase*, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique); - IDBIndexBackendImpl(IDBSQLiteDatabase*, const String& name, const String& storeName, const String& keyPath, bool unique); - - SQLiteDatabase& sqliteDatabase() const; + IDBIndexBackendImpl(IDBBackingStore*, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique); + IDBIndexBackendImpl(IDBBackingStore*, const String& name, const String& storeName, const String& keyPath, bool unique); - static void openCursorInternal(ScriptExecutionContext*, PassRefPtr, PassRefPtr, unsigned short direction, bool objectCursor, PassRefPtr, PassRefPtr); + static void openCursorInternal(ScriptExecutionContext*, PassRefPtr, PassRefPtr, unsigned short direction, IDBCursorBackendInterface::CursorType, PassRefPtr, PassRefPtr); static void getInternal(ScriptExecutionContext*, PassRefPtr, PassRefPtr, bool getObject, PassRefPtr); static const int64_t InvalidId = 0; - RefPtr m_database; + RefPtr m_backingStore; int64_t m_id; String m_name; diff --git a/Source/WebCore/storage/IDBKey.cpp b/Source/WebCore/storage/IDBKey.cpp index 5f45543..35156e8 100644 --- a/Source/WebCore/storage/IDBKey.cpp +++ b/Source/WebCore/storage/IDBKey.cpp @@ -28,9 +28,6 @@ #if ENABLE(INDEXED_DATABASE) -#include "SQLiteStatement.h" -#include "SerializedScriptValue.h" - namespace WebCore { IDBKey::IDBKey() @@ -42,35 +39,21 @@ IDBKey::~IDBKey() { } -PassRefPtr IDBKey::fromQuery(SQLiteStatement& query, int baseColumn) -{ - if (query.columnCount() <= baseColumn) - return 0; - - if (!query.isColumnNull(baseColumn)) - return IDBKey::createString(query.getColumnText(baseColumn)); - - if (!query.isColumnNull(baseColumn + 1)) - return IDBKey::createDate(query.getColumnDouble(baseColumn + 1)); - - if (!query.isColumnNull(baseColumn + 2)) - return IDBKey::createNumber(query.getColumnDouble(baseColumn + 2)); - - return IDBKey::createNull(); -} - -bool IDBKey::isEqual(IDBKey* other) +bool IDBKey::isLessThan(const IDBKey* other) const { - if (!other || other->m_type != m_type) + ASSERT(other); + if (other->m_type < m_type) + return true; + if (other->m_type > m_type) return false; switch (m_type) { case StringType: - return other->m_string == m_string; + return codePointCompare(other->m_string, m_string) > 0; case DateType: - return other->m_date == m_date; + return other->m_date > m_date; case NumberType: - return other->m_number == m_number; + return other->m_number > m_number; case NullType: return true; } @@ -79,106 +62,24 @@ bool IDBKey::isEqual(IDBKey* other) return false; } -String IDBKey::whereSyntax(String qualifiedTableName) const -{ - switch (m_type) { - case IDBKey::StringType: - return qualifiedTableName + "keyString = ? AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL "; - case IDBKey::NumberType: - return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber = ? "; - case IDBKey::DateType: - return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate = ? AND " + qualifiedTableName + "keyNumber IS NULL "; - case IDBKey::NullType: - return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL "; - } - - ASSERT_NOT_REACHED(); - return ""; -} - -String IDBKey::lowerCursorWhereFragment(String comparisonOperator, String qualifiedTableName) +bool IDBKey::isEqual(const IDBKey* other) const { - switch (m_type) { - case StringType: - return "? " + comparisonOperator + " " + qualifiedTableName + "keyString AND "; - case DateType: - return "(? " + comparisonOperator + " " + qualifiedTableName + "keyDate OR NOT " + qualifiedTableName + "keyString IS NULL) AND "; - case NumberType: - return "(? " + comparisonOperator + " " + qualifiedTableName + "keyNumber OR NOT " + qualifiedTableName + "keyString IS NULL OR NOT " + qualifiedTableName + "keyDate IS NULL) AND "; - case NullType: - if (comparisonOperator == "<") - return "NOT(" + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL) AND "; - return ""; // If it's =, the upper bound half will do the constraining. If it's <=, then that's a no-op. - } - ASSERT_NOT_REACHED(); - return ""; -} + if (!other || other->m_type != m_type) + return false; -String IDBKey::upperCursorWhereFragment(String comparisonOperator, String qualifiedTableName) -{ switch (m_type) { case StringType: - return "(" + qualifiedTableName + "keyString " + comparisonOperator + " ? OR " + qualifiedTableName + "keyString IS NULL) AND "; + return other->m_string == m_string; case DateType: - return "(" + qualifiedTableName + "keyDate " + comparisonOperator + " ? OR " + qualifiedTableName + "keyDate IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND "; + return other->m_date == m_date; case NumberType: - return "(" + qualifiedTableName + "keyNumber " + comparisonOperator + " ? OR " + qualifiedTableName + "keyNumber IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND "; + return other->m_number == m_number; case NullType: - if (comparisonOperator == "<") - return "0 != 0 AND "; - return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL AND "; - } - ASSERT_NOT_REACHED(); - return ""; -} - -// Returns the number of items bound. -int IDBKey::bind(SQLiteStatement& query, int column) const -{ - switch (m_type) { - case IDBKey::StringType: - query.bindText(column, m_string); - return 1; - case IDBKey::DateType: - query.bindDouble(column, m_date); - return 1; - case IDBKey::NumberType: - query.bindDouble(column, m_number); - return 1; - case IDBKey::NullType: - return 0; + return true; } ASSERT_NOT_REACHED(); - return 0; -} - -void IDBKey::bindWithNulls(SQLiteStatement& query, int baseColumn) const -{ - switch (m_type) { - case IDBKey::StringType: - query.bindText(baseColumn + 0, m_string); - query.bindNull(baseColumn + 1); - query.bindNull(baseColumn + 2); - break; - case IDBKey::DateType: - query.bindNull(baseColumn + 0); - query.bindDouble(baseColumn + 1, m_date); - query.bindNull(baseColumn + 2); - break; - case IDBKey::NumberType: - query.bindNull(baseColumn + 0); - query.bindNull(baseColumn + 1); - query.bindDouble(baseColumn + 2, m_number); - break; - case IDBKey::NullType: - query.bindNull(baseColumn + 0); - query.bindNull(baseColumn + 1); - query.bindNull(baseColumn + 2); - break; - default: - ASSERT_NOT_REACHED(); - } + return false; } } // namespace WebCore diff --git a/Source/WebCore/storage/IDBKey.h b/Source/WebCore/storage/IDBKey.h index 9118743..5816ce3 100644 --- a/Source/WebCore/storage/IDBKey.h +++ b/Source/WebCore/storage/IDBKey.h @@ -34,8 +34,6 @@ namespace WebCore { -class SQLiteStatement; - class IDBKey : public ThreadSafeShared { public: static PassRefPtr createNull() @@ -99,14 +97,8 @@ public: return m_number; } - static PassRefPtr fromQuery(SQLiteStatement& query, int baseColumn); - - bool isEqual(IDBKey* other); - String whereSyntax(String qualifiedTableName = "") const; - String lowerCursorWhereFragment(String comparisonOperator, String qualifiedTableName = ""); - String upperCursorWhereFragment(String comparisonOperator, String qualifiedTableName = ""); - int bind(SQLiteStatement& query, int column) const; - void bindWithNulls(SQLiteStatement& query, int baseColumn) const; + bool isLessThan(const IDBKey* other) const; + bool isEqual(const IDBKey* other) const; using ThreadSafeShared::ref; using ThreadSafeShared::deref; diff --git a/Source/WebCore/storage/IDBKeyPathBackendImpl.cpp b/Source/WebCore/storage/IDBKeyPathBackendImpl.cpp index b7c45c3..4f0fcee 100644 --- a/Source/WebCore/storage/IDBKeyPathBackendImpl.cpp +++ b/Source/WebCore/storage/IDBKeyPathBackendImpl.cpp @@ -37,4 +37,10 @@ void IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(const Ve // FIXME: Implement this method once JSC supports WireFormat for SerializedScriptValue. } +PassRefPtr IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(PassRefPtr key, PassRefPtr value, const String& keyPath) +{ + // FIXME: Implement this method once JSC supports WireFormat for SerializedScriptValue. + return 0; +} + #endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/storage/IDBKeyPathBackendImpl.h b/Source/WebCore/storage/IDBKeyPathBackendImpl.h index 32af5e3..1c76232 100644 --- a/Source/WebCore/storage/IDBKeyPathBackendImpl.h +++ b/Source/WebCore/storage/IDBKeyPathBackendImpl.h @@ -38,6 +38,7 @@ class SerializedScriptValue; class IDBKeyPathBackendImpl { public: static void createIDBKeysFromSerializedValuesAndKeyPath(const Vector, 0>& values, const String& keyPath, Vector, 0>& keys); + static PassRefPtr injectIDBKeyIntoSerializedValue(PassRefPtr, PassRefPtr, const String& keyPath); }; } diff --git a/Source/WebCore/storage/IDBKeyRange.cpp b/Source/WebCore/storage/IDBKeyRange.cpp index 142b3bd..4f4144b 100644 --- a/Source/WebCore/storage/IDBKeyRange.cpp +++ b/Source/WebCore/storage/IDBKeyRange.cpp @@ -56,31 +56,11 @@ PassRefPtr IDBKeyRange::upperBound(PassRefPtr bound, bool o return IDBKeyRange::create(0, bound, false, open); } -PassRefPtr IDBKeyRange::bound(PassRefPtr lower, PassRefPtr upper, const OptionsObject& options) +PassRefPtr IDBKeyRange::bound(PassRefPtr lower, PassRefPtr upper, bool lowerOpen, bool upperOpen) { - bool lowerOpen = false; - bool upperOpen = false; - options.getKeyBool("lowerOpen", lowerOpen); - options.getKeyBool("upperOpen", upperOpen); return IDBKeyRange::create(lower, upper, lowerOpen, upperOpen); } -String IDBKeyRange::lowerWhereClauseComparisonOperator() const -{ - ASSERT(m_lower); - if (m_lowerOpen) - return "<"; - return "<="; -} - -String IDBKeyRange::upperWhereClauseComparisonOperator() const -{ - ASSERT(m_upper); - if (m_upperOpen) - return "<"; - return "<="; -} - } // namespace WebCore #endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/storage/IDBKeyRange.h b/Source/WebCore/storage/IDBKeyRange.h index 8af48fe..636a5c1 100644 --- a/Source/WebCore/storage/IDBKeyRange.h +++ b/Source/WebCore/storage/IDBKeyRange.h @@ -43,19 +43,15 @@ public: } ~IDBKeyRange() { } - PassRefPtr lower() const { return m_lower; } PassRefPtr upper() const { return m_upper; } bool lowerOpen() const { return m_lowerOpen; } bool upperOpen() const { return m_upperOpen; } - String lowerWhereClauseComparisonOperator() const; - String upperWhereClauseComparisonOperator() const; - static PassRefPtr only(PassRefPtr value); static PassRefPtr lowerBound(PassRefPtr bound, bool open = false); static PassRefPtr upperBound(PassRefPtr bound, bool open = false); - static PassRefPtr bound(PassRefPtr lower, PassRefPtr upper, const OptionsObject& = OptionsObject()); + static PassRefPtr bound(PassRefPtr lower, PassRefPtr upper, bool lowerOpen = false, bool upperOpen = false); private: IDBKeyRange(PassRefPtr lower, PassRefPtr upper, bool lowerOpen, bool upperOpen); diff --git a/Source/WebCore/storage/IDBKeyRange.idl b/Source/WebCore/storage/IDBKeyRange.idl index d7fa075..6dd4c85 100644 --- a/Source/WebCore/storage/IDBKeyRange.idl +++ b/Source/WebCore/storage/IDBKeyRange.idl @@ -37,7 +37,7 @@ module storage { [ClassMethod] IDBKeyRange only(in IDBKey value); [ClassMethod] IDBKeyRange lowerBound(in IDBKey bound, in [Optional] boolean open); [ClassMethod] IDBKeyRange upperBound(in IDBKey bound, in [Optional] boolean open); - [ClassMethod] IDBKeyRange bound(in IDBKey lower, in IDBKey upper, in [Optional] OptionsObject options); + [ClassMethod] IDBKeyRange bound(in IDBKey lower, in IDBKey upper, in [Optional] boolean lowerOpen, in [Optional] boolean upperOpen); }; } diff --git a/Source/WebCore/storage/IDBObjectStore.cpp b/Source/WebCore/storage/IDBObjectStore.cpp index 53ae279..1a3e741 100644 --- a/Source/WebCore/storage/IDBObjectStore.cpp +++ b/Source/WebCore/storage/IDBObjectStore.cpp @@ -71,8 +71,10 @@ PassRefPtr IDBObjectStore::get(ScriptExecutionContext* context, Pass { RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); m_objectStore->get(key, request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; + } return request.release(); } @@ -80,36 +82,44 @@ PassRefPtr IDBObjectStore::add(ScriptExecutionContext* context, Pass { RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); m_objectStore->put(value, key, IDBObjectStoreBackendInterface::AddOnly, request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; - return request; + } + return request.release(); } PassRefPtr IDBObjectStore::put(ScriptExecutionContext* context, PassRefPtr value, PassRefPtr key, ExceptionCode& ec) { RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); m_objectStore->put(value, key, IDBObjectStoreBackendInterface::AddOrUpdate, request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; - return request; + } + return request.release(); } PassRefPtr IDBObjectStore::deleteFunction(ScriptExecutionContext* context, PassRefPtr key, ExceptionCode& ec) { RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); m_objectStore->deleteFunction(key, request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; - return request; + } + return request.release(); } PassRefPtr IDBObjectStore::clear(ScriptExecutionContext* context, ExceptionCode& ec) { RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); m_objectStore->clear(request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; - return request; + } + return request.release(); } PassRefPtr IDBObjectStore::createIndex(const String& name, const String& keyPath, const OptionsObject& options, ExceptionCode& ec) @@ -121,7 +131,7 @@ PassRefPtr IDBObjectStore::createIndex(const String& name, const Strin ASSERT(!index != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa. if (!index) return 0; - return IDBIndex::create(index.release(), m_transaction.get()); + return IDBIndex::create(index.release(), this, m_transaction.get()); } PassRefPtr IDBObjectStore::index(const String& name, ExceptionCode& ec) @@ -130,7 +140,7 @@ PassRefPtr IDBObjectStore::index(const String& name, ExceptionCode& ec ASSERT(!index != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa. if (!index) return 0; - return IDBIndex::create(index.release(), m_transaction.get()); + return IDBIndex::create(index.release(), this, m_transaction.get()); } void IDBObjectStore::deleteIndex(const String& name, ExceptionCode& ec) @@ -147,9 +157,12 @@ PassRefPtr IDBObjectStore::openCursor(ScriptExecutionContext* contex } RefPtr request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); + request->setCursorType(IDBCursorBackendInterface::ObjectStoreCursor); m_objectStore->openCursor(range, direction, request, m_transaction->backend(), ec); - if (ec) + if (ec) { + request->markEarlyDeath(); return 0; + } return request.release(); } diff --git a/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp b/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp index 921bbab..0433ed7 100644 --- a/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp +++ b/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp @@ -30,6 +30,7 @@ #include "CrossThreadTask.h" #include "DOMStringList.h" +#include "IDBBackingStore.h" #include "IDBBindingUtilities.h" #include "IDBCallbacks.h" #include "IDBCursorBackendImpl.h" @@ -40,12 +41,8 @@ #include "IDBKeyPath.h" #include "IDBKeyPathBackendImpl.h" #include "IDBKeyRange.h" -#include "IDBSQLiteDatabase.h" #include "IDBTransactionBackendInterface.h" #include "ScriptExecutionContext.h" -#include "SQLiteDatabase.h" -#include "SQLiteStatement.h" -#include "SQLiteTransaction.h" namespace WebCore { @@ -53,8 +50,8 @@ IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl() { } -IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBSQLiteDatabase* database, int64_t id, const String& name, const String& keyPath, bool autoIncrement) - : m_database(database) +IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBBackingStore* backingStore, int64_t id, const String& name, const String& keyPath, bool autoIncrement) + : m_backingStore(backingStore) , m_id(id) , m_name(name) , m_keyPath(keyPath) @@ -64,8 +61,8 @@ IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBSQLiteDatabase* database loadIndexes(); } -IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBSQLiteDatabase* database, const String& name, const String& keyPath, bool autoIncrement) - : m_database(database) +IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBBackingStore* backingStore, const String& name, const String& keyPath, bool autoIncrement) + : m_backingStore(backingStore) , m_id(InvalidId) , m_name(name) , m_keyPath(keyPath) @@ -82,17 +79,6 @@ PassRefPtr IDBObjectStoreBackendImpl::indexNames() const return indexNames.release(); } -static String whereClause(IDBKey* key) -{ - return "WHERE objectStoreId = ? AND " + key->whereSyntax(); -} - -static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key) -{ - query.bindInt64(1, id); - key->bind(query, 2); -} - void IDBObjectStoreBackendImpl::get(PassRefPtr prpKey, PassRefPtr prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec) { RefPtr objectStore = this; @@ -104,22 +90,13 @@ void IDBObjectStoreBackendImpl::get(PassRefPtr prpKey, PassRefPtr objectStore, PassRefPtr key, PassRefPtr callbacks) { - SQLiteStatement query(objectStore->sqliteDatabase(), "SELECT keyString, keyDate, keyNumber, value FROM ObjectStoreData " + whereClause(key.get())); - bool ok = query.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - - bindWhereClause(query, objectStore->id(), key.get()); - if (query.step() != SQLResultRow) { + String wireData = objectStore->m_backingStore->getObjectStoreRecord(objectStore->id(), *key); + if (wireData.isNull()) { callbacks->onSuccess(SerializedScriptValue::undefinedValue()); return; } - ASSERT((key->type() == IDBKey::StringType) != query.isColumnNull(0)); - ASSERT((key->type() == IDBKey::DateType) != query.isColumnNull(1)); - ASSERT((key->type() == IDBKey::NumberType) != query.isColumnNull(2)); - - callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnBlobAsString(3))); - ASSERT(query.step() != SQLResultRow); + callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData)); } static PassRefPtr fetchKeyFromKeyPath(SerializedScriptValue* value, const String& keyPath) @@ -134,49 +111,9 @@ static PassRefPtr fetchKeyFromKeyPath(SerializedScriptValue* value, cons return keys[0].release(); } -static bool putObjectStoreData(SQLiteDatabase& db, IDBKey* key, SerializedScriptValue* value, int64_t objectStoreId, int64_t& dataRowId) +static PassRefPtr injectKeyIntoKeyPath(PassRefPtr key, PassRefPtr value, const String& keyPath) { - String sql = dataRowId != IDBObjectStoreBackendImpl::InvalidId ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?" - : "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)"; - SQLiteStatement query(db, sql); - if (query.prepare() != SQLResultOk) - return false; - key->bindWithNulls(query, 1); - query.bindBlob(4, value->toWireString()); - if (dataRowId != IDBDatabaseBackendImpl::InvalidId) - query.bindInt64(5, dataRowId); - else - query.bindInt64(5, objectStoreId); - - if (query.step() != SQLResultDone) - return false; - - if (dataRowId == IDBDatabaseBackendImpl::InvalidId) - dataRowId = db.lastInsertRowID(); - - return true; -} - -static bool deleteIndexData(SQLiteDatabase& db, int64_t objectStoreDataId) -{ - SQLiteStatement deleteQuery(db, "DELETE FROM IndexData WHERE objectStoreDataId = ?"); - if (deleteQuery.prepare() != SQLResultOk) - return false; - deleteQuery.bindInt64(1, objectStoreDataId); - - return deleteQuery.step() == SQLResultDone; -} - -static bool putIndexData(SQLiteDatabase& db, IDBKey* key, int64_t indexId, int64_t objectStoreDataId) -{ - SQLiteStatement putQuery(db, "INSERT INTO IndexData (keyString, keyDate, keyNumber, indexId, objectStoreDataId) VALUES (?, ?, ?, ?, ?)"); - if (putQuery.prepare() != SQLResultOk) - return false; - key->bindWithNulls(putQuery, 1); - putQuery.bindInt64(4, indexId); - putQuery.bindInt64(5, objectStoreDataId); - - return putQuery.step() == SQLResultDone; + return IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(key, value, keyPath); } void IDBObjectStoreBackendImpl::put(PassRefPtr prpValue, PassRefPtr prpKey, PutMode putMode, PassRefPtr prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec) @@ -197,7 +134,7 @@ void IDBObjectStoreBackendImpl::put(PassRefPtr prpValue, ec = IDBDatabaseException::NOT_ALLOWED_ERR; } -PassRefPtr IDBObjectStoreBackendImpl::selectKeyForPut(IDBObjectStoreBackendImpl* objectStore, SerializedScriptValue* value, IDBKey* key, PutMode putMode, IDBCallbacks* callbacks) +PassRefPtr IDBObjectStoreBackendImpl::selectKeyForPut(IDBObjectStoreBackendImpl* objectStore, IDBKey* key, PutMode putMode, IDBCallbacks* callbacks, RefPtr& value) { if (putMode == CursorUpdate) ASSERT(key); @@ -220,19 +157,24 @@ PassRefPtr IDBObjectStoreBackendImpl::selectKeyForPut(IDBObjectStoreBack if (!hasKeyPath) return objectStore->genAutoIncrementKey(); - RefPtr keyPathKey = fetchKeyFromKeyPath(value, objectStore->m_keyPath); + RefPtr keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath); if (keyPathKey) { objectStore->resetAutoIncrementKeyCache(); return keyPathKey; } - // FIXME: Generate auto increment key, and inject it through the key path. - callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Adding data to object stores with auto increment and in-line keys not yet supported.")); - return 0; + RefPtr autoIncKey = objectStore->genAutoIncrementKey(); + RefPtr valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath); + if (!valueAfterInjection) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The generated key could not be inserted into the object using the keyPath.")); + return 0; + } + value = valueAfterInjection; + return autoIncKey.release(); } if (hasKeyPath) { - RefPtr keyPathKey = fetchKeyFromKeyPath(value, objectStore->m_keyPath); + RefPtr keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath); if (!keyPathKey) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The key could not be fetched from the keyPath.")); @@ -258,7 +200,7 @@ PassRefPtr IDBObjectStoreBackendImpl::selectKeyForPut(IDBObjectStoreBack void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr objectStore, PassRefPtr prpValue, PassRefPtr prpKey, PutMode putMode, PassRefPtr callbacks, PassRefPtr transaction) { RefPtr value = prpValue; - RefPtr key = selectKeyForPut(objectStore.get(), value.get(), prpKey.get(), putMode, callbacks.get()); + RefPtr key = selectKeyForPut(objectStore.get(), prpKey.get(), putMode, callbacks.get(), value); if (!key) return; @@ -285,12 +227,9 @@ void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr< indexKeys.append(key.release()); } - SQLiteStatement getQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get())); - bool ok = getQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + int64_t dataRowId = InvalidId; + bool isExistingValue = objectStore->m_backingStore->keyExistsInObjectStore(objectStore->id(), *key, dataRowId); - bindWhereClause(getQuery, objectStore->id(), key.get()); - bool isExistingValue = getQuery.step() == SQLResultRow; if (putMode == AddOnly && isExistingValue) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store.")); return; @@ -298,15 +237,14 @@ void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr< // Before this point, don't do any mutation. After this point, rollback the transaction in case of error. - int64_t dataRowId = isExistingValue ? getQuery.getColumnInt(0) : InvalidId; - if (!putObjectStoreData(objectStore->sqliteDatabase(), key.get(), value.get(), objectStore->id(), dataRowId)) { + if (!objectStore->m_backingStore->putObjectStoreRecord(objectStore->id(), *key, value->toWireString(), dataRowId, dataRowId == InvalidId)) { // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors. callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage.")); transaction->abort(); return; } - if (!deleteIndexData(objectStore->sqliteDatabase(), dataRowId)) { + if (!objectStore->m_backingStore->deleteIndexDataForRecord(dataRowId)) { // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors. callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage.")); transaction->abort(); @@ -315,7 +253,9 @@ void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr< int i = 0; for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it, ++i) { - if (!putIndexData(objectStore->sqliteDatabase(), indexKeys[i].get(), it->second->id(), dataRowId)) { + if (!it->second->hasValidId()) + continue; // The index object has been created, but does not exist in the database yet. + if (!objectStore->m_backingStore->putIndexDataForRecord(it->second->id(), *indexKeys[i], dataRowId)) { // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors. callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage.")); transaction->abort(); @@ -343,35 +283,13 @@ void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr prpKey, PassRe void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr objectStore, PassRefPtr key, PassRefPtr callbacks) { - SQLiteStatement idQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get())); - bool ok = idQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - bindWhereClause(idQuery, objectStore->id(), key.get()); - if (idQuery.step() != SQLResultRow) { + int64_t id; + if (!objectStore->m_backingStore->keyExistsInObjectStore(objectStore->id(), *key, id)) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store.")); return; } - int64_t id = idQuery.getColumnInt64(0); - - SQLiteStatement osQuery(objectStore->sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE id = ?"); - ok = osQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - - osQuery.bindInt64(1, id); - - ok = osQuery.step() == SQLResultDone; - ASSERT_UNUSED(ok, ok); - - SQLiteStatement indexQuery(objectStore->sqliteDatabase(), "DELETE FROM IndexData WHERE objectStoreDataId = ?"); - ok = indexQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - - indexQuery.bindInt64(1, id); - - ok = indexQuery.step() == SQLResultDone; - ASSERT_UNUSED(ok, ok); - + objectStore->m_backingStore->deleteObjectStoreRecord(objectStore->id(), id); callbacks->onSuccess(SerializedScriptValue::nullValue()); } @@ -389,22 +307,46 @@ void IDBObjectStoreBackendImpl::clear(PassRefPtr prpCallbacks, IDB ec = IDBDatabaseException::NOT_ALLOWED_ERR; } -static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id) +void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr objectStore, PassRefPtr callbacks) { - SQLiteStatement deleteQuery(db, sql); - bool ok = deleteQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. - deleteQuery.bindInt64(1, id); - ok = deleteQuery.step() == SQLResultDone; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + objectStore->m_backingStore->clearObjectStore(objectStore->id()); + callbacks->onSuccess(SerializedScriptValue::undefinedValue()); } -void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr objectStore, PassRefPtr callbacks) -{ - doDelete(objectStore->sqliteDatabase(), "DELETE FROM IndexData WHERE objectStoreDataId IN (SELECT id FROM ObjectStoreData WHERE objectStoreId = ?)", objectStore->id()); - doDelete(objectStore->sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStore->id()); +namespace { +class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback { +public: + PopulateIndexCallback(IDBBackingStore& backingStore, const String& indexKeyPath, int64_t indexId) + : m_backingStore(backingStore) + , m_indexKeyPath(indexKeyPath) + , m_indexId(indexId) + { + } - callbacks->onSuccess(SerializedScriptValue::undefinedValue()); + virtual bool callback(int64_t objectStoreDataId, const String& value) + { + RefPtr objectValue = SerializedScriptValue::createFromWire(value); + RefPtr indexKey = fetchKeyFromKeyPath(objectValue.get(), m_indexKeyPath); + + if (!m_backingStore.putIndexDataForRecord(m_indexId, *indexKey, objectStoreDataId)) + return false; + + return true; + } + +private: + IDBBackingStore& m_backingStore; + const String& m_indexKeyPath; + int64_t m_indexId; +}; +} + +static bool populateIndex(IDBBackingStore& backingStore, int64_t objectStoreId, int64_t indexId, const String& indexKeyPath) +{ + PopulateIndexCallback callback(backingStore, indexKeyPath, indexId); + if (!backingStore.forEachObjectStoreRecord(objectStoreId, callback)) + return false; + return true; } PassRefPtr IDBObjectStoreBackendImpl::createIndex(const String& name, const String& keyPath, bool unique, IDBTransactionBackendInterface* transaction, ExceptionCode& ec) @@ -418,7 +360,7 @@ PassRefPtr IDBObjectStoreBackendImpl::createIndex(cons return 0; } - RefPtr index = IDBIndexBackendImpl::create(m_database.get(), name, m_name, keyPath, unique); + RefPtr index = IDBIndexBackendImpl::create(m_backingStore.get(), name, m_name, keyPath, unique); ASSERT(index->name() == name); RefPtr objectStore = this; @@ -435,21 +377,19 @@ PassRefPtr IDBObjectStoreBackendImpl::createIndex(cons void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr objectStore, PassRefPtr index, PassRefPtr transaction) { - SQLiteStatement insert(objectStore->sqliteDatabase(), "INSERT INTO Indexes (objectStoreId, name, keyPath, isUnique) VALUES (?, ?, ?, ?)"); - if (insert.prepare() != SQLResultOk) { + int64_t id; + if (!objectStore->m_backingStore->createIndex(objectStore->m_id, index->name(), index->keyPath(), index->unique(), id)) { transaction->abort(); return; } - insert.bindInt64(1, objectStore->m_id); - insert.bindText(2, index->name()); - insert.bindText(3, index->keyPath()); - insert.bindInt(4, static_cast(index->unique())); - if (insert.step() != SQLResultDone) { + + index->setId(id); + + if (!populateIndex(*objectStore->m_backingStore, objectStore->m_id, id, index->keyPath())) { transaction->abort(); return; } - int64_t id = objectStore->sqliteDatabase().lastInsertRowID(); - index->setId(id); + transaction->didCompleteTaskEvents(); } @@ -488,9 +428,7 @@ void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBa void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr objectStore, PassRefPtr index, PassRefPtr transaction) { - doDelete(objectStore->sqliteDatabase(), "DELETE FROM Indexes WHERE id = ?", index->id()); - doDelete(objectStore->sqliteDatabase(), "DELETE FROM IndexData WHERE indexId = ?", index->id()); - + objectStore->m_backingStore->deleteIndex(index->id()); transaction->didCompleteTaskEvents(); } @@ -506,64 +444,32 @@ void IDBObjectStoreBackendImpl::openCursor(PassRefPtr prpRange, uns void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr objectStore, PassRefPtr range, unsigned short tmpDirection, PassRefPtr callbacks, PassRefPtr transaction) { - bool lowerBound = range && range->lower(); - bool upperBound = range && range->upper(); - - // Several files depend on this order of selects. - String sql = "SELECT id, keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE "; - if (lowerBound) - sql += range->lower()->lowerCursorWhereFragment(range->lowerWhereClauseComparisonOperator()); - if (upperBound) - sql += range->upper()->upperCursorWhereFragment(range->upperWhereClauseComparisonOperator()); - sql += "objectStoreId = ? ORDER BY "; - IDBCursor::Direction direction = static_cast(tmpDirection); - if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) - sql += "keyString, keyDate, keyNumber"; - else - sql += "keyString DESC, keyDate DESC, keyNumber DESC"; - - OwnPtr query = adoptPtr(new SQLiteStatement(objectStore->sqliteDatabase(), sql)); - bool ok = query->prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - - int currentColumn = 1; - if (lowerBound) - currentColumn += range->lower()->bind(*query, currentColumn); - if (upperBound) - currentColumn += range->upper()->bind(*query, currentColumn); - query->bindInt64(currentColumn, objectStore->id()); - - if (query->step() != SQLResultRow) { + + RefPtr backingStoreCursor = objectStore->m_backingStore->openObjectStoreCursor(objectStore->id(), range.get(), direction); + if (!backingStoreCursor) { callbacks->onSuccess(SerializedScriptValue::nullValue()); return; } - RefPtr cursor = IDBCursorBackendImpl::create(objectStore->m_database.get(), range, direction, query.release(), true, transaction.get(), objectStore.get()); + RefPtr cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get()); callbacks->onSuccess(cursor.release()); } void IDBObjectStoreBackendImpl::loadIndexes() { - SQLiteStatement indexQuery(sqliteDatabase(), "SELECT id, name, keyPath, isUnique FROM Indexes WHERE objectStoreId = ?"); - bool ok = indexQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - - indexQuery.bindInt64(1, m_id); + Vector ids; + Vector names; + Vector keyPaths; + Vector uniqueFlags; + m_backingStore->getIndexes(m_id, ids, names, keyPaths, uniqueFlags); - while (indexQuery.step() == SQLResultRow) { - int64_t id = indexQuery.getColumnInt64(0); - String name = indexQuery.getColumnText(1); - String keyPath = indexQuery.getColumnText(2); - bool unique = !!indexQuery.getColumnInt(3); + ASSERT(names.size() == ids.size()); + ASSERT(keyPaths.size() == ids.size()); + ASSERT(uniqueFlags.size() == ids.size()); - m_indexes.set(name, IDBIndexBackendImpl::create(m_database.get(), id, name, m_name, keyPath, unique)); - } -} - -SQLiteDatabase& IDBObjectStoreBackendImpl::sqliteDatabase() const -{ - return m_database->db(); + for (size_t i = 0; i < ids.size(); i++) + m_indexes.set(names[i], IDBIndexBackendImpl::create(m_backingStore.get(), ids[i], names[i], m_name, keyPaths[i], uniqueFlags[i])); } void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr objectStore, PassRefPtr index) @@ -584,19 +490,7 @@ PassRefPtr IDBObjectStoreBackendImpl::genAutoIncrementKey() if (m_autoIncrementNumber > 0) return IDBKey::createNumber(m_autoIncrementNumber++); - String sql = "SELECT max(keyNumber) + 1 FROM ObjectStoreData WHERE objectStoreId = ? AND keyString IS NULL AND keyDate IS NULL"; - - SQLiteStatement query(sqliteDatabase(), sql); - bool ok = query.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); - - query.bindInt64(1, id()); - - if (query.step() != SQLResultRow || query.isColumnNull(0)) - m_autoIncrementNumber = 1; - else - m_autoIncrementNumber = static_cast(query.getColumnDouble(0)); - + m_autoIncrementNumber = static_cast(m_backingStore->nextAutoIncrementNumber(id())); return IDBKey::createNumber(m_autoIncrementNumber++); } diff --git a/Source/WebCore/storage/IDBObjectStoreBackendImpl.h b/Source/WebCore/storage/IDBObjectStoreBackendImpl.h index b54f9fd..4479d1e 100644 --- a/Source/WebCore/storage/IDBObjectStoreBackendImpl.h +++ b/Source/WebCore/storage/IDBObjectStoreBackendImpl.h @@ -34,22 +34,21 @@ namespace WebCore { +class IDBBackingStore; class IDBDatabaseBackendImpl; class IDBIndexBackendImpl; -class IDBSQLiteDatabase; class IDBTransactionBackendInterface; -class SQLiteDatabase; class ScriptExecutionContext; class IDBObjectStoreBackendImpl : public IDBObjectStoreBackendInterface { public: - static PassRefPtr create(IDBSQLiteDatabase* database, int64_t id, const String& name, const String& keyPath, bool autoIncrement) + static PassRefPtr create(IDBBackingStore* backingStore, int64_t id, const String& name, const String& keyPath, bool autoIncrement) { - return adoptRef(new IDBObjectStoreBackendImpl(database, id, name, keyPath, autoIncrement)); + return adoptRef(new IDBObjectStoreBackendImpl(backingStore, id, name, keyPath, autoIncrement)); } - static PassRefPtr create(IDBSQLiteDatabase* database, const String& name, const String& keyPath, bool autoIncrement) + static PassRefPtr create(IDBBackingStore* backingStore, const String& name, const String& keyPath, bool autoIncrement) { - return adoptRef(new IDBObjectStoreBackendImpl(database, name, keyPath, autoIncrement)); + return adoptRef(new IDBObjectStoreBackendImpl(backingStore, name, keyPath, autoIncrement)); } virtual ~IDBObjectStoreBackendImpl(); @@ -78,14 +77,13 @@ public: virtual void openCursor(PassRefPtr range, unsigned short direction, PassRefPtr, IDBTransactionBackendInterface*, ExceptionCode&); private: - IDBObjectStoreBackendImpl(IDBSQLiteDatabase*, int64_t id, const String& name, const String& keyPath, bool autoIncrement); - IDBObjectStoreBackendImpl(IDBSQLiteDatabase*, const String& name, const String& keyPath, bool autoIncrement); + IDBObjectStoreBackendImpl(IDBBackingStore*, int64_t id, const String& name, const String& keyPath, bool autoIncrement); + IDBObjectStoreBackendImpl(IDBBackingStore*, const String& name, const String& keyPath, bool autoIncrement); void loadIndexes(); - SQLiteDatabase& sqliteDatabase() const; PassRefPtr genAutoIncrementKey(); void resetAutoIncrementKeyCache() { m_autoIncrementNumber = -1; } - static PassRefPtr selectKeyForPut(IDBObjectStoreBackendImpl*, SerializedScriptValue*, IDBKey*, PutMode, IDBCallbacks*); + static PassRefPtr selectKeyForPut(IDBObjectStoreBackendImpl*, IDBKey*, PutMode, IDBCallbacks*, RefPtr&); static void getInternal(ScriptExecutionContext*, PassRefPtr, PassRefPtr key, PassRefPtr); static void putInternal(ScriptExecutionContext*, PassRefPtr, PassRefPtr, PassRefPtr, PutMode, PassRefPtr, PassRefPtr); @@ -99,7 +97,7 @@ private: static void removeIndexFromMap(ScriptExecutionContext*, PassRefPtr, PassRefPtr); static void addIndexToMap(ScriptExecutionContext*, PassRefPtr, PassRefPtr); - RefPtr m_database; + RefPtr m_backingStore; int64_t m_id; String m_name; diff --git a/Source/WebCore/storage/IDBRequest.cpp b/Source/WebCore/storage/IDBRequest.cpp index e7498ec..e1837fc 100644 --- a/Source/WebCore/storage/IDBRequest.cpp +++ b/Source/WebCore/storage/IDBRequest.cpp @@ -36,13 +36,12 @@ #include "EventListener.h" #include "EventNames.h" #include "EventQueue.h" -#include "IDBCursor.h" +#include "IDBCursorWithValue.h" #include "IDBDatabase.h" +#include "IDBEventDispatcher.h" #include "IDBIndex.h" -#include "IDBErrorEvent.h" -#include "IDBObjectStore.h" #include "IDBPendingTransactionMonitor.h" -#include "IDBSuccessEvent.h" +#include "IDBTransaction.h" namespace WebCore { @@ -53,47 +52,157 @@ PassRefPtr IDBRequest::create(ScriptExecutionContext* context, PassR IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr source, IDBTransaction* transaction) : ActiveDOMObject(context, this) + , m_errorCode(0) , m_source(source) , m_transaction(transaction) , m_readyState(LOADING) , m_finished(false) + , m_cursorType(IDBCursorBackendInterface::InvalidCursorType) { - if (m_transaction) + if (m_transaction) { + m_transaction->registerRequest(this); IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend()); + } } IDBRequest::~IDBRequest() { + ASSERT(m_readyState == DONE || m_readyState == EarlyDeath); + if (m_transaction) + m_transaction->unregisterRequest(this); +} + +PassRefPtr IDBRequest::result(ExceptionCode& ec) const +{ + if (m_readyState != DONE) { + ec = IDBDatabaseException::NOT_ALLOWED_ERR; + return 0; + } + return m_result; +} + +unsigned short IDBRequest::errorCode(ExceptionCode& ec) const +{ + if (m_readyState != DONE) { + ec = IDBDatabaseException::NOT_ALLOWED_ERR; + return 0; + } + return m_errorCode; +} + +String IDBRequest::webkitErrorMessage(ExceptionCode& ec) const +{ + if (m_readyState != DONE) { + ec = IDBDatabaseException::NOT_ALLOWED_ERR; + return String(); + } + return m_errorMessage; +} + +PassRefPtr IDBRequest::source() const +{ + return m_source; +} + +PassRefPtr IDBRequest::transaction() const +{ + return m_transaction; +} + +unsigned short IDBRequest::readyState() const +{ + ASSERT(m_readyState == LOADING || m_readyState == DONE); + return m_readyState; +} + +void IDBRequest::markEarlyDeath() +{ + ASSERT(m_readyState == LOADING); + m_readyState = EarlyDeath; } bool IDBRequest::resetReadyState(IDBTransaction* transaction) { ASSERT(!m_finished); ASSERT(scriptExecutionContext()); + ASSERT(transaction == m_transaction); if (m_readyState != DONE) return false; - m_transaction = transaction; m_readyState = LOADING; + m_result.clear(); + m_errorCode = 0; + m_errorMessage = String(); IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend()); return true; } +IDBAny* IDBRequest::source() +{ + return m_source.get(); +} + +void IDBRequest::abort() +{ + if (m_readyState != LOADING) { + ASSERT(m_readyState == DONE); + return; + } + + ASSERT(scriptExecutionContext()->isDocument()); + EventQueue* eventQueue = static_cast(scriptExecutionContext())->eventQueue(); + for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) { + bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get()); + ASSERT_UNUSED(removed, removed); + } + m_enqueuedEvents.clear(); + + m_errorCode = 0; + m_errorMessage = String(); + m_result.clear(); + onError(IDBDatabaseError::create(IDBDatabaseException::ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled.")); +} + +void IDBRequest::setCursorType(IDBCursorBackendInterface::CursorType cursorType) +{ + ASSERT(m_cursorType == IDBCursorBackendInterface::InvalidCursorType); + m_cursorType = cursorType; +} + void IDBRequest::onError(PassRefPtr error) { - enqueueEvent(IDBErrorEvent::create(m_source, *error)); + ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result); + m_errorCode = error->code(); + m_errorMessage = error->message(); + enqueueEvent(Event::create(eventNames().errorEvent, true, true)); +} + +static PassRefPtr createSuccessEvent() +{ + return Event::create(eventNames().successEvent, false, false); } void IDBRequest::onSuccess(PassRefPtr backend) { - enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(IDBCursor::create(backend, this, m_transaction.get())))); + ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result); + ASSERT(m_cursorType != IDBCursorBackendInterface::InvalidCursorType); + if (m_cursorType == IDBCursorBackendInterface::IndexKeyCursor) + m_result = IDBAny::create(IDBCursor::create(backend, this, m_source.get(), m_transaction.get())); + else + m_result = IDBAny::create(IDBCursorWithValue::create(backend, this, m_source.get(), m_transaction.get())); + enqueueEvent(createSuccessEvent()); } void IDBRequest::onSuccess(PassRefPtr backend) { - enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(IDBDatabase::create(scriptExecutionContext(), backend)))); + ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result); + RefPtr idbDatabase = IDBDatabase::create(scriptExecutionContext(), backend); + idbDatabase->open(); + + m_result = IDBAny::create(idbDatabase.release()); + enqueueEvent(createSuccessEvent()); } void IDBRequest::onSuccess(PassRefPtr backend) @@ -103,16 +212,14 @@ void IDBRequest::onSuccess(PassRefPtr backend) void IDBRequest::onSuccess(PassRefPtr idbKey) { - enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(idbKey))); -} - -void IDBRequest::onSuccess(PassRefPtr backend) -{ - ASSERT_NOT_REACHED(); // FIXME: This method should go away. + ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result); + m_result = IDBAny::create(idbKey); + enqueueEvent(createSuccessEvent()); } void IDBRequest::onSuccess(PassRefPtr prpBackend) { + ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result); if (!scriptExecutionContext()) return; @@ -125,12 +232,16 @@ void IDBRequest::onSuccess(PassRefPtr prpBackend m_source->idbDatabase()->setSetVersionTransaction(frontend.get()); IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend()); - enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(frontend.release()))); + + m_result = IDBAny::create(frontend.release()); + enqueueEvent(createSuccessEvent()); } void IDBRequest::onSuccess(PassRefPtr serializedScriptValue) { - enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(serializedScriptValue))); + ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result); + m_result = IDBAny::create(serializedScriptValue); + enqueueEvent(createSuccessEvent()); } bool IDBRequest::hasPendingActivity() const @@ -141,6 +252,11 @@ bool IDBRequest::hasPendingActivity() const return !m_finished || ActiveDOMObject::hasPendingActivity(); } +void IDBRequest::onBlocked() +{ + ASSERT_NOT_REACHED(); +} + ScriptExecutionContext* IDBRequest::scriptExecutionContext() const { return ActiveDOMObject::scriptExecutionContext(); @@ -149,10 +265,17 @@ ScriptExecutionContext* IDBRequest::scriptExecutionContext() const bool IDBRequest::dispatchEvent(PassRefPtr event) { ASSERT(!m_finished); + ASSERT(m_enqueuedEvents.size()); ASSERT(scriptExecutionContext()); ASSERT(event->target() == this); ASSERT(m_readyState < DONE); - m_readyState = DONE; + if (event->type() != eventNames().blockedEvent) + m_readyState = DONE; + + for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) { + if (m_enqueuedEvents[i].get() == event.get()) + m_enqueuedEvents.remove(i); + } Vector > targets; targets.append(this); @@ -165,26 +288,29 @@ bool IDBRequest::dispatchEvent(PassRefPtr event) targets.append(m_transaction->db()); } - ASSERT(event->isIDBErrorEvent() || event->isIDBSuccessEvent()); - bool dontPreventDefault = static_cast(event.get())->dispatch(targets); + // FIXME: When we allow custom event dispatching, this will probably need to change. + ASSERT(event->type() == eventNames().successEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().blockedEvent); + bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets); - // If the event's result was of type IDBCursor, then it's possible for us to - // fire again (unless the transaction completes). - if (event->isIDBSuccessEvent()) { - RefPtr any = static_cast(event.get())->result(); - if (any->type() != IDBAny::IDBCursorType) - m_finished = true; - } else + // If the result was of type IDBCursor, then we'll fire again. + if (m_result && m_result->type() != IDBAny::IDBCursorType && m_result->type() != IDBAny::IDBCursorWithValueType) m_finished = true; if (m_transaction) { - if (dontPreventDefault && event->isIDBErrorEvent()) + // If an error event and the default wasn't prevented... + if (dontPreventDefault && event->type() == eventNames().errorEvent) m_transaction->backend()->abort(); m_transaction->backend()->didCompleteTaskEvents(); } return dontPreventDefault; } +void IDBRequest::uncaughtExceptionInEventHandler() +{ + if (m_transaction) + m_transaction->backend()->abort(); +} + void IDBRequest::enqueueEvent(PassRefPtr event) { ASSERT(!m_finished); @@ -195,7 +321,8 @@ void IDBRequest::enqueueEvent(PassRefPtr event) ASSERT(scriptExecutionContext()->isDocument()); EventQueue* eventQueue = static_cast(scriptExecutionContext())->eventQueue(); event->setTarget(this); - eventQueue->enqueueEvent(event); + eventQueue->enqueueEvent(event.get()); + m_enqueuedEvents.append(event); } EventTargetData* IDBRequest::eventTargetData() diff --git a/Source/WebCore/storage/IDBRequest.h b/Source/WebCore/storage/IDBRequest.h index 5c31318..b6b4e5b 100644 --- a/Source/WebCore/storage/IDBRequest.h +++ b/Source/WebCore/storage/IDBRequest.h @@ -36,12 +36,12 @@ #include "EventListener.h" #include "EventNames.h" #include "EventTarget.h" +#include "ExceptionCode.h" #include "IDBAny.h" #include "IDBCallbacks.h" namespace WebCore { -class IDBEvent; class IDBTransaction; class IDBRequest : public IDBCallbacks, public EventTarget, public ActiveDOMObject { @@ -49,16 +49,28 @@ public: static PassRefPtr create(ScriptExecutionContext*, PassRefPtr source, IDBTransaction*); virtual ~IDBRequest(); + PassRefPtr result(ExceptionCode&) const; + unsigned short errorCode(ExceptionCode&) const; + String webkitErrorMessage(ExceptionCode&) const; + PassRefPtr source() const; + PassRefPtr transaction() const; + // Defined in the IDL enum ReadyState { LOADING = 1, - DONE = 2 + DONE = 2, + EarlyDeath = 3 }; - unsigned short readyState() const { return m_readyState; } + unsigned short readyState() const; + DEFINE_ATTRIBUTE_EVENT_LISTENER(success); DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + void markEarlyDeath(); bool resetReadyState(IDBTransaction*); + void setCursorType(IDBCursorBackendInterface::CursorType); + IDBAny* source(); + void abort(); // IDBCallbacks virtual void onError(PassRefPtr); @@ -66,9 +78,9 @@ public: virtual void onSuccess(PassRefPtr); virtual void onSuccess(PassRefPtr); virtual void onSuccess(PassRefPtr); - virtual void onSuccess(PassRefPtr); virtual void onSuccess(PassRefPtr); virtual void onSuccess(PassRefPtr); + virtual void onBlocked(); // ActiveDOMObject virtual bool hasPendingActivity() const; @@ -78,15 +90,19 @@ public: virtual ScriptExecutionContext* scriptExecutionContext() const; virtual bool dispatchEvent(PassRefPtr); bool dispatchEvent(PassRefPtr event, ExceptionCode& ec) { return EventTarget::dispatchEvent(event, ec); } + virtual void uncaughtExceptionInEventHandler(); using ThreadSafeShared::ref; using ThreadSafeShared::deref; -private: +protected: IDBRequest(ScriptExecutionContext*, PassRefPtr source, IDBTransaction*); - void enqueueEvent(PassRefPtr); + RefPtr m_result; + unsigned short m_errorCode; + String m_errorMessage; +private: // EventTarget virtual void refEventTarget() { ref(); } virtual void derefEventTarget() { deref(); } @@ -98,6 +114,10 @@ private: ReadyState m_readyState; bool m_finished; // Is it possible that we'll fire any more events? If not, we're finished. + Vector > m_enqueuedEvents; + + // Only used if the result type will be a cursor. + IDBCursorBackendInterface::CursorType m_cursorType; EventTargetData m_eventTargetData; }; diff --git a/Source/WebCore/storage/IDBRequest.idl b/Source/WebCore/storage/IDBRequest.idl index 58872f0..6ce2036 100644 --- a/Source/WebCore/storage/IDBRequest.idl +++ b/Source/WebCore/storage/IDBRequest.idl @@ -32,6 +32,14 @@ module storage { Conditional=INDEXED_DATABASE, EventTarget ] IDBRequest { + readonly attribute IDBAny result + getter raises (IDBDatabaseException); + readonly attribute unsigned short errorCode + getter raises (IDBDatabaseException); + readonly attribute [ConvertNullStringTo=Undefined] DOMString webkitErrorMessage + getter raises (IDBDatabaseException); + readonly attribute IDBAny source; + readonly attribute IDBTransaction transaction; // States const unsigned short LOADING = 1; diff --git a/Source/WebCore/storage/IDBSQLiteDatabase.cpp b/Source/WebCore/storage/IDBSQLiteDatabase.cpp deleted file mode 100644 index e881917..0000000 --- a/Source/WebCore/storage/IDBSQLiteDatabase.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBSQLiteDatabase.h" - -#if ENABLE(INDEXED_DATABASE) - -#include "IDBFactoryBackendImpl.h" - -namespace WebCore { - -IDBSQLiteDatabase::IDBSQLiteDatabase(String identifier, IDBFactoryBackendImpl* factory) - : m_identifier(identifier) - , m_factory(factory) -{ -} - -IDBSQLiteDatabase::~IDBSQLiteDatabase() -{ - m_factory->removeSQLiteDatabase(m_identifier); -} - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/storage/IDBSQLiteDatabase.h b/Source/WebCore/storage/IDBSQLiteDatabase.h deleted file mode 100644 index 0556506..0000000 --- a/Source/WebCore/storage/IDBSQLiteDatabase.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBSQLiteDatabase_h -#define IDBSQLiteDatabase_h - -#if ENABLE(INDEXED_DATABASE) - -#include "SQLiteDatabase.h" -#include -#include -#include - -namespace WebCore { - -class IDBFactoryBackendImpl; - -class IDBSQLiteDatabase : public RefCounted { -public: - static PassRefPtr create(String identifier, IDBFactoryBackendImpl* factory) - { - return adoptRef(new IDBSQLiteDatabase(identifier, factory)); - } - ~IDBSQLiteDatabase(); - - SQLiteDatabase& db() { return m_db; } - -private: - IDBSQLiteDatabase(String identifier, IDBFactoryBackendImpl* factory); - - SQLiteDatabase m_db; - String m_identifier; - RefPtr m_factory; -}; - -} // namespace WebCore - -#endif - -#endif // IDBSQLiteDatabase_h diff --git a/Source/WebCore/storage/IDBSuccessEvent.cpp b/Source/WebCore/storage/IDBSuccessEvent.cpp deleted file mode 100644 index 110b78b..0000000 --- a/Source/WebCore/storage/IDBSuccessEvent.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBSuccessEvent.h" - -#if ENABLE(INDEXED_DATABASE) - -#include "EventNames.h" -#include "IDBAny.h" - -namespace WebCore { - -PassRefPtr IDBSuccessEvent::create(PassRefPtr source, PassRefPtr result) -{ - return adoptRef(new IDBSuccessEvent(source, result)); -} - -IDBSuccessEvent::IDBSuccessEvent(PassRefPtr source, PassRefPtr result) - : IDBEvent(eventNames().successEvent, source, false) - , m_result(result) -{ -} - -IDBSuccessEvent::~IDBSuccessEvent() -{ -} - -PassRefPtr IDBSuccessEvent::result() -{ - return m_result; -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/storage/IDBSuccessEvent.h b/Source/WebCore/storage/IDBSuccessEvent.h deleted file mode 100644 index 5be660a..0000000 --- a/Source/WebCore/storage/IDBSuccessEvent.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBSuccessEvent_h -#define IDBSuccessEvent_h - -#if ENABLE(INDEXED_DATABASE) - -#include "IDBEvent.h" -#include -#include - -namespace WebCore { - -class IDBAny; - -class IDBSuccessEvent : public IDBEvent { -public: - static PassRefPtr create(PassRefPtr source, PassRefPtr result); - // FIXME: Need to allow creation of these events from JS. - virtual ~IDBSuccessEvent(); - - PassRefPtr result(); - - virtual bool isIDBSuccessEvent() const { return true; } - -private: - IDBSuccessEvent(PassRefPtr source, PassRefPtr result); - - RefPtr m_result; -}; - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) - -#endif // IDBEvent_h diff --git a/Source/WebCore/storage/IDBSuccessEvent.idl b/Source/WebCore/storage/IDBSuccessEvent.idl deleted file mode 100644 index b4ea7d2..0000000 --- a/Source/WebCore/storage/IDBSuccessEvent.idl +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -module storage { - - interface [ - Conditional=INDEXED_DATABASE - ] IDBSuccessEvent : IDBEvent { - readonly attribute IDBAny result; - }; -} diff --git a/Source/WebCore/storage/IDBTransaction.cpp b/Source/WebCore/storage/IDBTransaction.cpp index 1f696b3..710bb76 100644 --- a/Source/WebCore/storage/IDBTransaction.cpp +++ b/Source/WebCore/storage/IDBTransaction.cpp @@ -31,10 +31,9 @@ #include "Document.h" #include "EventException.h" #include "EventQueue.h" -#include "IDBAbortEvent.h" -#include "IDBCompleteEvent.h" #include "IDBDatabase.h" #include "IDBDatabaseException.h" +#include "IDBEventDispatcher.h" #include "IDBIndex.h" #include "IDBObjectStore.h" #include "IDBObjectStoreBackendInterface.h" @@ -104,14 +103,31 @@ void IDBTransaction::abort() m_backend->abort(); } +void IDBTransaction::registerRequest(IDBRequest* request) +{ + m_childRequests.add(request); +} + +void IDBTransaction::unregisterRequest(IDBRequest* request) +{ + // If we aborted the request, it will already have been removed. + m_childRequests.remove(request); +} + void IDBTransaction::onAbort() { - enqueueEvent(IDBAbortEvent::create(IDBAny::create(this))); + while (!m_childRequests.isEmpty()) { + IDBRequest* request = *m_childRequests.begin(); + m_childRequests.remove(request); + request->abort(); + } + + enqueueEvent(Event::create(eventNames().abortEvent, true, false)); } void IDBTransaction::onComplete() { - enqueueEvent(IDBCompleteEvent::create(IDBAny::create(this))); + enqueueEvent(Event::create(eventNames().completeEvent, false, false)); } bool IDBTransaction::hasPendingActivity() const @@ -139,8 +155,9 @@ bool IDBTransaction::dispatchEvent(PassRefPtr event) targets.append(this); targets.append(db()); - ASSERT(event->isIDBAbortEvent() || event->isIDBCompleteEvent()); - return static_cast(event.get())->dispatch(targets); + // FIXME: When we allow custom event dispatching, this will probably need to change. + ASSERT(event->type() == eventNames().completeEvent || event->type() == eventNames().abortEvent); + return IDBEventDispatcher::dispatch(event.get(), targets); } bool IDBTransaction::canSuspend() const diff --git a/Source/WebCore/storage/IDBTransaction.h b/Source/WebCore/storage/IDBTransaction.h index ff4feb6..b5778ad 100644 --- a/Source/WebCore/storage/IDBTransaction.h +++ b/Source/WebCore/storage/IDBTransaction.h @@ -62,6 +62,9 @@ public: PassRefPtr objectStore(const String& name, ExceptionCode&); void abort(); + void registerRequest(IDBRequest*); + void unregisterRequest(IDBRequest*); + DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); DEFINE_ATTRIBUTE_EVENT_LISTENER(complete); DEFINE_ATTRIBUTE_EVENT_LISTENER(error); @@ -100,6 +103,8 @@ private: unsigned short m_mode; bool m_finished; // Is it possible that we'll fire any more events or allow any new transactions? If not, we're finished. + ListHashSet m_childRequests; + EventTargetData m_eventTargetData; }; diff --git a/Source/WebCore/storage/IDBTransactionBackendImpl.cpp b/Source/WebCore/storage/IDBTransactionBackendImpl.cpp index 1357838..b5b883f 100644 --- a/Source/WebCore/storage/IDBTransactionBackendImpl.cpp +++ b/Source/WebCore/storage/IDBTransactionBackendImpl.cpp @@ -28,10 +28,10 @@ #if ENABLE(INDEXED_DATABASE) +#include "IDBBackingStore.h" #include "IDBDatabaseBackendImpl.h" #include "IDBDatabaseException.h" #include "IDBTransactionCoordinator.h" -#include "SQLiteDatabase.h" namespace WebCore { @@ -45,7 +45,7 @@ IDBTransactionBackendImpl::IDBTransactionBackendImpl(DOMStringList* objectStores , m_mode(mode) , m_state(Unused) , m_database(database) - , m_transaction(new SQLiteTransaction(database->sqliteDatabase())) + , m_transaction(database->backingStore()->createTransaction()) , m_taskTimer(this, &IDBTransactionBackendImpl::taskTimerFired) , m_taskEventTimer(this, &IDBTransactionBackendImpl::taskEventTimerFired) , m_pendingEvents(0) diff --git a/Source/WebCore/storage/IDBTransactionBackendImpl.h b/Source/WebCore/storage/IDBTransactionBackendImpl.h index 1297e74..912a239 100644 --- a/Source/WebCore/storage/IDBTransactionBackendImpl.h +++ b/Source/WebCore/storage/IDBTransactionBackendImpl.h @@ -29,9 +29,9 @@ #if ENABLE(INDEXED_DATABASE) #include "DOMStringList.h" +#include "IDBBackingStore.h" #include "IDBTransactionBackendInterface.h" #include "IDBTransactionCallbacks.h" -#include "SQLiteTransaction.h" #include "Timer.h" #include #include @@ -81,7 +81,7 @@ private: TaskQueue m_taskQueue; TaskQueue m_abortTaskQueue; - OwnPtr m_transaction; + RefPtr m_transaction; // FIXME: delete the timer once we have threads instead. Timer m_taskTimer; diff --git a/Source/WebCore/storage/IDBTransactionBackendInterface.h b/Source/WebCore/storage/IDBTransactionBackendInterface.h index 9b1fce6..1b370af 100644 --- a/Source/WebCore/storage/IDBTransactionBackendInterface.h +++ b/Source/WebCore/storage/IDBTransactionBackendInterface.h @@ -38,7 +38,6 @@ namespace WebCore { class IDBObjectStoreBackendInterface; class IDBTransactionCallbacks; -class SQLiteDatabase; // This class is shared by IDBTransaction (async) and IDBTransactionSync (sync). // This is implemented by IDBTransactionBackendImpl and optionally others (in order to proxy @@ -61,4 +60,3 @@ public: #endif #endif // IDBTransactionBackendInterface_h - diff --git a/Source/WebCore/storage/IDBTransactionCoordinator.cpp b/Source/WebCore/storage/IDBTransactionCoordinator.cpp index f867f42..edaff2c 100644 --- a/Source/WebCore/storage/IDBTransactionCoordinator.cpp +++ b/Source/WebCore/storage/IDBTransactionCoordinator.cpp @@ -31,7 +31,6 @@ #include "IDBDatabaseBackendImpl.h" #include "IDBObjectStoreBackendInterface.h" #include "IDBTransactionBackendImpl.h" -#include "SQLiteDatabase.h" #include "ScriptExecutionContext.h" namespace WebCore { diff --git a/Source/WebCore/storage/IDBVersionChangeEvent.cpp b/Source/WebCore/storage/IDBVersionChangeEvent.cpp new file mode 100644 index 0000000..5fd9d8b --- /dev/null +++ b/Source/WebCore/storage/IDBVersionChangeEvent.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBVersionChangeEvent.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "EventNames.h" +#include "IDBAny.h" + +namespace WebCore { + +PassRefPtr IDBVersionChangeEvent::create(const String& version, const AtomicString& eventType) +{ + return adoptRef(new IDBVersionChangeEvent(version, eventType)); +} + +IDBVersionChangeEvent::IDBVersionChangeEvent(const String& version, const AtomicString& eventType) + : Event(eventType, false /*canBubble*/, false /*cancelable*/) + , m_version(version) +{ +} + +IDBVersionChangeEvent::~IDBVersionChangeEvent() +{ +} + +String IDBVersionChangeEvent::version() +{ + return m_version; +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/storage/IDBVersionChangeEvent.h b/Source/WebCore/storage/IDBVersionChangeEvent.h new file mode 100644 index 0000000..efd360f --- /dev/null +++ b/Source/WebCore/storage/IDBVersionChangeEvent.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBVersionChangeEvent_h +#define IDBVersionChangeEvent_h + +#if ENABLE(INDEXED_DATABASE) + +#include "Event.h" +#include "PlatformString.h" +#include +#include + +namespace WebCore { + +class IDBAny; + +class IDBVersionChangeEvent : public Event { +public: + static PassRefPtr create(const String& version, const AtomicString& eventType); + // FIXME: Need to allow creation of these events from JS. + virtual ~IDBVersionChangeEvent(); + + virtual bool isIDBVersionChangeEvent() const { return true; } + + virtual String version(); + +private: + IDBVersionChangeEvent(const String& version, const AtomicString& eventType); + + String m_version; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBVersionChangeEvent_h diff --git a/Source/WebCore/storage/IDBVersionChangeEvent.idl b/Source/WebCore/storage/IDBVersionChangeEvent.idl new file mode 100644 index 0000000..c6a4171 --- /dev/null +++ b/Source/WebCore/storage/IDBVersionChangeEvent.idl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE + ] IDBVersionChangeEvent : Event { + readonly attribute DOMString version; + }; +} diff --git a/Source/WebCore/storage/IDBVersionChangeRequest.cpp b/Source/WebCore/storage/IDBVersionChangeRequest.cpp new file mode 100644 index 0000000..8c5416e --- /dev/null +++ b/Source/WebCore/storage/IDBVersionChangeRequest.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBVersionChangeRequest.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBVersionChangeEvent.h" +#include "ScriptExecutionContext.h" + +namespace WebCore { + +PassRefPtr IDBVersionChangeRequest::create(ScriptExecutionContext* context, PassRefPtr source, const String& version) +{ + return adoptRef(new IDBVersionChangeRequest(context, source, version)); +} + +IDBVersionChangeRequest::IDBVersionChangeRequest(ScriptExecutionContext* context, PassRefPtr source, const String& version) + : IDBRequest(context, source, 0) + , m_version(version) +{ +} + +IDBVersionChangeRequest::~IDBVersionChangeRequest() +{ +} + +void IDBVersionChangeRequest::onBlocked() +{ + ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result); + enqueueEvent(IDBVersionChangeEvent::create(m_version, eventNames().blockedEvent)); +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/storage/IDBVersionChangeRequest.h b/Source/WebCore/storage/IDBVersionChangeRequest.h new file mode 100644 index 0000000..32cf4c0 --- /dev/null +++ b/Source/WebCore/storage/IDBVersionChangeRequest.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBVersionChangeRequest_h +#define IDBVersionChangeRequest_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBRequest.h" + +namespace WebCore { + +class IDBVersionChangeRequest : public IDBRequest { +public: + static PassRefPtr create(ScriptExecutionContext*, PassRefPtr source, const String& version); + virtual ~IDBVersionChangeRequest(); + + virtual void onBlocked(); + + DEFINE_ATTRIBUTE_EVENT_LISTENER(blocked); + +private: + IDBVersionChangeRequest(ScriptExecutionContext*, PassRefPtr source, const String& version); + + String m_version; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBRequest_h diff --git a/Source/WebCore/storage/IDBVersionChangeRequest.idl b/Source/WebCore/storage/IDBVersionChangeRequest.idl new file mode 100644 index 0000000..ffac735 --- /dev/null +++ b/Source/WebCore/storage/IDBVersionChangeRequest.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE, + EventTarget + ] IDBVersionChangeRequest : IDBRequest { + attribute EventListener onblocked; + }; +} diff --git a/Source/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp b/Source/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp index 38b2983..e6a1ad5 100644 --- a/Source/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp +++ b/Source/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp @@ -28,7 +28,9 @@ #if ENABLE(INDEXED_DATABASE) +#include "IDBKey.h" #include "PlatformBridge.h" +#include "SerializedScriptValue.h" namespace WebCore { @@ -37,6 +39,11 @@ void IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(const Ve PlatformBridge::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys); } +PassRefPtr IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(PassRefPtr key, PassRefPtr value, const String& keyPath) +{ + return PlatformBridge::injectIDBKeyIntoSerializedValue(key, value, keyPath); +} + } // namespace WebCore #endif -- cgit v1.1