diff options
Diffstat (limited to 'WebCore/storage')
31 files changed, 364 insertions, 121 deletions
diff --git a/WebCore/storage/AbstractDatabase.cpp b/WebCore/storage/AbstractDatabase.cpp index 8d3bf1e..c8b8894 100644 --- a/WebCore/storage/AbstractDatabase.cpp +++ b/WebCore/storage/AbstractDatabase.cpp @@ -41,6 +41,7 @@ #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> #include <wtf/StdLibExtras.h> +#include <wtf/text/CString.h> #include <wtf/text/StringHash.h> namespace WebCore { diff --git a/WebCore/storage/Database.cpp b/WebCore/storage/Database.cpp index 089f9ee..920f75b 100644 --- a/WebCore/storage/Database.cpp +++ b/WebCore/storage/Database.cpp @@ -54,6 +54,7 @@ #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> #include <wtf/StdLibExtras.h> +#include <wtf/text/CString.h> #if USE(JSC) #include "JSDOMWindow.h" diff --git a/WebCore/storage/DatabaseSync.cpp b/WebCore/storage/DatabaseSync.cpp index 9c654a1..5634a60 100644 --- a/WebCore/storage/DatabaseSync.cpp +++ b/WebCore/storage/DatabaseSync.cpp @@ -42,6 +42,7 @@ #include "SecurityOrigin.h" #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> +#include <wtf/text/CString.h> namespace WebCore { diff --git a/WebCore/storage/DatabaseTracker.cpp b/WebCore/storage/DatabaseTracker.cpp index 1a13612..0b47842 100644 --- a/WebCore/storage/DatabaseTracker.cpp +++ b/WebCore/storage/DatabaseTracker.cpp @@ -46,6 +46,7 @@ #include "SQLiteStatement.h" #include <wtf/MainThread.h> #include <wtf/StdLibExtras.h> +#include <wtf/text/CString.h> using namespace std; diff --git a/WebCore/storage/IDBAny.cpp b/WebCore/storage/IDBAny.cpp index 7303fd6..45b166d 100644 --- a/WebCore/storage/IDBAny.cpp +++ b/WebCore/storage/IDBAny.cpp @@ -123,7 +123,7 @@ void IDBAny::set(PassRefPtr<IDBDatabase> value) void IDBAny::set(PassRefPtr<IDBIndex> value) { ASSERT(m_type == UndefinedType); - m_type = IDBDatabaseType; + m_type = IDBIndexType; m_idbIndex = value; } diff --git a/WebCore/storage/IDBCursor.cpp b/WebCore/storage/IDBCursor.cpp index 52945f8..c1c077b 100644 --- a/WebCore/storage/IDBCursor.cpp +++ b/WebCore/storage/IDBCursor.cpp @@ -60,7 +60,7 @@ PassRefPtr<IDBKey> IDBCursor::key() const PassRefPtr<IDBAny> IDBCursor::value() const { - return IDBAny::create(m_backend->value().get()); + return m_backend->value(); } PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value) diff --git a/WebCore/storage/IDBCursorBackendImpl.cpp b/WebCore/storage/IDBCursorBackendImpl.cpp index 4cbac0e..3a4dd67 100644 --- a/WebCore/storage/IDBCursorBackendImpl.cpp +++ b/WebCore/storage/IDBCursorBackendImpl.cpp @@ -32,6 +32,7 @@ #include "IDBDatabaseBackendImpl.h" #include "IDBDatabaseError.h" #include "IDBDatabaseException.h" +#include "IDBIndexBackendImpl.h" #include "IDBKeyRange.h" #include "IDBObjectStoreBackendImpl.h" #include "IDBRequest.h" @@ -46,6 +47,17 @@ IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl> , m_keyRange(keyRange) , m_direction(direction) , m_query(query) + , m_isSerializedScriptValueCursor(true) +{ + loadCurrentRow(); +} + +IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBIndexBackendImpl> idbIndex, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor) + : m_idbIndex(idbIndex) + , m_keyRange(keyRange) + , m_direction(direction) + , m_query(query) + , m_isSerializedScriptValueCursor(isSerializedScriptValueCursor) { loadCurrentRow(); } @@ -65,13 +77,19 @@ PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const return m_currentKey; } -PassRefPtr<SerializedScriptValue> IDBCursorBackendImpl::value() const +PassRefPtr<IDBAny> IDBCursorBackendImpl::value() const { - return m_currentValue; + if (m_isSerializedScriptValueCursor) + return IDBAny::create(m_currentSerializedScriptValue.get()); + return IDBAny::create(m_currentIDBKeyValue.get()); } void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> callbacks) { + // FIXME: This method doesn't update indexes. It's dangerous to call in its current state. + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Not implemented.")); + return; + RefPtr<SerializedScriptValue> value = prpValue; if (!m_query || m_currentId == InvalidId) { @@ -81,7 +99,7 @@ void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, Pa } String sql = "UPDATE ObjectStoreData SET value = ? WHERE id = ?"; - SQLiteStatement updateQuery(m_idbObjectStore->database()->sqliteDatabase(), sql); + SQLiteStatement updateQuery(database()->sqliteDatabase(), sql); bool ok = updateQuery.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. @@ -90,7 +108,8 @@ void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, Pa ok = updateQuery.step() == SQLResultDone; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. - m_currentValue = value.release(); + if (m_isSerializedScriptValueCursor) + m_currentSerializedScriptValue = value.release(); callbacks->onSuccess(); } @@ -102,7 +121,8 @@ void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPt m_query = 0; m_currentId = InvalidId; m_currentKey = 0; - m_currentValue = 0; + m_currentSerializedScriptValue = 0; + m_currentIDBKeyValue = 0; callbacks->onSuccess(); return; } @@ -126,6 +146,10 @@ void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPt void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> callbacks) { + // FIXME: This method doesn't update indexes. It's dangerous to call in its current state. + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Not implemented.")); + return; + if (!m_query || m_currentId == InvalidId) { // FIXME: Use the proper error code when it's specced. callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Operation not possible.")); @@ -133,7 +157,7 @@ void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> callbacks) } String sql = "DELETE FROM ObjectStoreData WHERE id = ?"; - SQLiteStatement deleteQuery(m_idbObjectStore->database()->sqliteDatabase(), sql); + SQLiteStatement deleteQuery(database()->sqliteDatabase(), sql); bool ok = deleteQuery.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. @@ -142,8 +166,8 @@ void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> callbacks) ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. m_currentId = InvalidId; - m_currentKey = 0; - m_currentValue = 0; + m_currentSerializedScriptValue = 0; + m_currentIDBKeyValue = 0; callbacks->onSuccess(); } @@ -151,16 +175,18 @@ void IDBCursorBackendImpl::loadCurrentRow() { // The column numbers depend on the query in IDBObjectStoreBackendImpl::openCursor. m_currentId = m_query->getColumnInt64(0); - if (!m_query->isColumnNull(1)) - m_currentKey = IDBKey::create(m_query->getColumnText(1)); - else if (!m_query->isColumnNull(2)) { - ASSERT_NOT_REACHED(); // FIXME: Implement date. - m_currentKey = IDBKey::create(); - } else if (!m_query->isColumnNull(3)) - m_currentKey = IDBKey::create(m_query->getColumnInt(3)); + m_currentKey = IDBKey::fromQuery(*m_query, 1); + if (m_isSerializedScriptValueCursor) + m_currentSerializedScriptValue = SerializedScriptValue::createFromWire(m_query->getColumnText(4)); else - m_currentKey = IDBKey::create(); - m_currentValue = SerializedScriptValue::createFromWire(m_query->getColumnText(4)); + m_currentIDBKeyValue = IDBKey::fromQuery(*m_query, 4); +} + +IDBDatabaseBackendImpl* IDBCursorBackendImpl::database() const +{ + if (m_idbObjectStore) + return m_idbObjectStore->database(); + return m_idbIndex->objectStore()->database(); } } // namespace WebCore diff --git a/WebCore/storage/IDBCursorBackendImpl.h b/WebCore/storage/IDBCursorBackendImpl.h index 3f7c4aa..b67ec70 100644 --- a/WebCore/storage/IDBCursorBackendImpl.h +++ b/WebCore/storage/IDBCursorBackendImpl.h @@ -37,6 +37,8 @@ namespace WebCore { +class IDBDatabaseBackendImpl; +class IDBIndexBackendImpl; class IDBKeyRange; class IDBObjectStoreBackendImpl; class SQLiteStatement; @@ -48,29 +50,42 @@ public: { return adoptRef(new IDBCursorBackendImpl(objectStore, keyRange, direction, query)); } + static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor) + { + return adoptRef(new IDBCursorBackendImpl(index, keyRange, direction, query, isSerializedScriptValueCursor)); + } virtual ~IDBCursorBackendImpl(); virtual unsigned short direction() const; virtual PassRefPtr<IDBKey> key() const; - virtual PassRefPtr<SerializedScriptValue> value() const; + virtual PassRefPtr<IDBAny> value() const; virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>); virtual void continueFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>); virtual void remove(PassRefPtr<IDBCallbacks>); private: IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query); + IDBCursorBackendImpl(PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor); void loadCurrentRow(); + IDBDatabaseBackendImpl* database() const; static const int64_t InvalidId = -1; + // Only one or the other should be used. RefPtr<IDBObjectStoreBackendImpl> m_idbObjectStore; + RefPtr<IDBIndexBackendImpl> m_idbIndex; + RefPtr<IDBKeyRange> m_keyRange; IDBCursor::Direction m_direction; OwnPtr<SQLiteStatement> m_query; + bool m_isSerializedScriptValueCursor; int64_t m_currentId; RefPtr<IDBKey> m_currentKey; - RefPtr<SerializedScriptValue> m_currentValue; + + // Only one of these will ever be used for each instance. Which depends on m_isSerializedScriptValueCursor. + RefPtr<SerializedScriptValue> m_currentSerializedScriptValue; + RefPtr<IDBKey> m_currentIDBKeyValue; }; } // namespace WebCore diff --git a/WebCore/storage/IDBCursorBackendInterface.h b/WebCore/storage/IDBCursorBackendInterface.h index acea955..4b209c4 100644 --- a/WebCore/storage/IDBCursorBackendInterface.h +++ b/WebCore/storage/IDBCursorBackendInterface.h @@ -46,7 +46,7 @@ public: virtual unsigned short direction() const = 0; virtual PassRefPtr<IDBKey> key() const = 0; - virtual PassRefPtr<SerializedScriptValue> value() const = 0; + virtual PassRefPtr<IDBAny> value() const = 0; virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>) = 0; virtual void continueFunction(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>) = 0; diff --git a/WebCore/storage/IDBFactory.cpp b/WebCore/storage/IDBFactory.cpp index d3a83a5..06c06ea 100644 --- a/WebCore/storage/IDBFactory.cpp +++ b/WebCore/storage/IDBFactory.cpp @@ -29,16 +29,19 @@ #include "config.h" #include "IDBFactory.h" +#if ENABLE(INDEXED_DATABASE) + #include "DOMStringList.h" #include "Document.h" #include "ExceptionCode.h" #include "Frame.h" +#include "GroupSettings.h" #include "IDBDatabase.h" #include "IDBFactoryBackendInterface.h" #include "IDBKeyRange.h" #include "IDBRequest.h" - -#if ENABLE(INDEXED_DATABASE) +#include "Page.h" +#include "PageGroup.h" namespace WebCore { @@ -61,11 +64,11 @@ PassRefPtr<IDBRequest> IDBFactory::open(ScriptExecutionContext* context, const S } Document* document = static_cast<Document*>(context); - if (!document->frame()) + if (!document->frame() || !document->page()) return 0; RefPtr<IDBRequest> request = IDBRequest::create(document, IDBAny::create(this)); - m_factoryBackend->open(name, description, request, document->securityOrigin(), document->frame()); + m_factoryBackend->open(name, description, request, document->securityOrigin(), document->frame(), document->page()->group().groupSettings()->indexedDBDatabasePath()); return request; } diff --git a/WebCore/storage/IDBFactoryBackendImpl.cpp b/WebCore/storage/IDBFactoryBackendImpl.cpp index 50cf778..d819c92 100644 --- a/WebCore/storage/IDBFactoryBackendImpl.cpp +++ b/WebCore/storage/IDBFactoryBackendImpl.cpp @@ -52,19 +52,21 @@ IDBFactoryBackendImpl::~IDBFactoryBackendImpl() { } -static PassOwnPtr<SQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOrigin, String name) +static PassOwnPtr<SQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOrigin, String name, const String& pathBase) { - String pathBase = "/tmp/temporary-indexed-db-files"; // FIXME: Write a PageGroupSettings class and have this value come from that. - 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; + 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; + } + + String databaseIdentifier = securityOrigin->databaseIdentifier(); + String santizedName = encodeForFileName(name); + path = pathByAppendingComponent(pathBase, databaseIdentifier + "_" + santizedName + ".indexeddb"); } - String databaseIdentifier = securityOrigin->databaseIdentifier(); - String santizedName = encodeForFileName(name); - String path = pathByAppendingComponent(pathBase, databaseIdentifier + "_" + santizedName + ".indexeddb"); - OwnPtr<SQLiteDatabase> sqliteDatabase = adoptPtr(new SQLiteDatabase()); if (!sqliteDatabase->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. @@ -98,13 +100,13 @@ static bool createTables(SQLiteDatabase* sqliteDatabase) "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)", "DROP TABLE IF EXISTS IndexData", - "CREATE TABLE IF NOT EXISTS IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexs(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL UNIQUE REFERENCES ObjectStoreData(id))", + "CREATE TABLE IF NOT EXISTS IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL UNIQUE REFERENCES ObjectStoreData(id))", "DROP INDEX IF EXISTS IndexData_composit", - "CREATE UNIQUE INDEX IF NOT EXISTS IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)", + "CREATE INDEX IF NOT EXISTS IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)", "DROP INDEX IF EXISTS IndexData_objectStoreDataId", - "CREATE UNIQUE INDEX IF NOT EXISTS IndexData_objectStoreDataId ON IndexData(objectStoreDataId)", + "CREATE INDEX IF NOT EXISTS IndexData_objectStoreDataId ON IndexData(objectStoreDataId)", "DROP INDEX IF EXISTS IndexData_indexId", - "CREATE UNIQUE INDEX IF NOT EXISTS IndexData_indexId ON IndexData(indexId)" + "CREATE INDEX IF NOT EXISTS IndexData_indexId ON IndexData(indexId)" }; for (size_t i = 0; i < arraysize(commands); ++i) { @@ -117,7 +119,7 @@ static bool createTables(SQLiteDatabase* sqliteDatabase) return true; } -void IDBFactoryBackendImpl::open(const String& name, const String& description, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*) +void IDBFactoryBackendImpl::open(const String& name, const String& description, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDir) { IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(name); if (it != m_databaseBackendMap.end()) { @@ -129,7 +131,7 @@ void IDBFactoryBackendImpl::open(const String& name, const String& description, // FIXME: Everything from now on should be done on another thread. - OwnPtr<SQLiteDatabase> sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), name); + OwnPtr<SQLiteDatabase> sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), name, dataDir); if (!sqliteDatabase || !createTables(sqliteDatabase.get())) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error.")); return; diff --git a/WebCore/storage/IDBFactoryBackendImpl.h b/WebCore/storage/IDBFactoryBackendImpl.h index c9a33da..f2e1af8 100644 --- a/WebCore/storage/IDBFactoryBackendImpl.h +++ b/WebCore/storage/IDBFactoryBackendImpl.h @@ -49,7 +49,7 @@ public: } virtual ~IDBFactoryBackendImpl(); - virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*); + virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir); virtual void abortPendingTransactions(const Vector<int>& pendingIDs); private: diff --git a/WebCore/storage/IDBFactoryBackendInterface.h b/WebCore/storage/IDBFactoryBackendInterface.h index c052bc2..e591271 100644 --- a/WebCore/storage/IDBFactoryBackendInterface.h +++ b/WebCore/storage/IDBFactoryBackendInterface.h @@ -51,7 +51,7 @@ public: static PassRefPtr<IDBFactoryBackendInterface> create(); virtual ~IDBFactoryBackendInterface() { } - virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*) = 0; + virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir) = 0; virtual void abortPendingTransactions(const Vector<int>& ids) = 0; }; diff --git a/WebCore/storage/IDBIndex.cpp b/WebCore/storage/IDBIndex.cpp index 62c1da8..5cd12dd 100644 --- a/WebCore/storage/IDBIndex.cpp +++ b/WebCore/storage/IDBIndex.cpp @@ -28,6 +28,12 @@ #if ENABLE(INDEXED_DATABASE) +#include "IDBCursorBackendInterface.h" +#include "IDBIndexBackendInterface.h" +#include "IDBKey.h" +#include "IDBKeyRange.h" +#include "IDBRequest.h" + namespace WebCore { IDBIndex::IDBIndex(PassRefPtr<IDBIndexBackendInterface> backend) @@ -39,6 +45,34 @@ IDBIndex::~IDBIndex() { } +PassRefPtr<IDBRequest> IDBIndex::openObjectCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_backend->openObjectCursor(keyRange, direction, request); + return request; +} + +PassRefPtr<IDBRequest> IDBIndex::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_backend->openCursor(keyRange, direction, request); + return request; +} + +PassRefPtr<IDBRequest> IDBIndex::getObject(ScriptExecutionContext* context, PassRefPtr<IDBKey> key) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_backend->getObject(key, request); + return request; +} + +PassRefPtr<IDBRequest> IDBIndex::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_backend->get(key, request); + return request; +} + } // namespace WebCore #endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBIndex.h b/WebCore/storage/IDBIndex.h index 5e716b7..45fcfa1 100644 --- a/WebCore/storage/IDBIndex.h +++ b/WebCore/storage/IDBIndex.h @@ -26,6 +26,7 @@ #ifndef IDBIndex_h #define IDBIndex_h +#include "IDBCursor.h" #include "IDBIndexBackendInterface.h" #include "PlatformString.h" #include <wtf/Forward.h> @@ -44,9 +45,15 @@ public: // Implement the IDL String name() const { return m_backend->name(); } + String storeName() const { return m_backend->storeName(); } String keyPath() const { return m_backend->keyPath(); } bool unique() const { return m_backend->unique(); } + PassRefPtr<IDBRequest> openObjectCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange> = 0, unsigned short direction = IDBCursor::NEXT); + PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange> = 0, unsigned short direction = IDBCursor::NEXT); + PassRefPtr<IDBRequest> getObject(ScriptExecutionContext*, PassRefPtr<IDBKey>); + PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey>); + private: IDBIndex(PassRefPtr<IDBIndexBackendInterface>); diff --git a/WebCore/storage/IDBIndex.idl b/WebCore/storage/IDBIndex.idl index 629481e..ba3ecea 100644 --- a/WebCore/storage/IDBIndex.idl +++ b/WebCore/storage/IDBIndex.idl @@ -29,15 +29,15 @@ module storage { Conditional=INDEXED_DATABASE ] IDBIndex { readonly attribute DOMString name; - // FIXME: Add "storeName". + readonly attribute DOMString storeName; readonly attribute DOMString keyPath; readonly attribute boolean unique; - // FIXME: Implement. - //IDBRequest openObjectCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction) raises (DOMException); - //IDBRequest openCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction) raises (DOMException); - //IDBRequest getObject(in IDBKey key) raises (DOMException); - //IDBRequest get(in IDBKey key) raises (DOMException); + // FIXME: All of these should raise on certain errors. + [CallWith=ScriptExecutionContext] IDBRequest openObjectCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction); + [CallWith=ScriptExecutionContext] IDBRequest openCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction); + [CallWith=ScriptExecutionContext] IDBRequest getObject(in IDBKey key); + [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key); }; } diff --git a/WebCore/storage/IDBIndexBackendImpl.cpp b/WebCore/storage/IDBIndexBackendImpl.cpp index 42aa62b..6f698c6 100644 --- a/WebCore/storage/IDBIndexBackendImpl.cpp +++ b/WebCore/storage/IDBIndexBackendImpl.cpp @@ -28,8 +28,14 @@ #if ENABLE(INDEXED_DATABASE) +#include "IDBCallbacks.h" +#include "IDBCursorBackendImpl.h" #include "IDBDatabaseBackendImpl.h" +#include "IDBDatabaseException.h" +#include "IDBKey.h" +#include "IDBKeyRange.h" #include "IDBObjectStoreBackendImpl.h" +#include "SQLiteDatabase.h" #include "SQLiteStatement.h" namespace WebCore { @@ -47,6 +53,98 @@ IDBIndexBackendImpl::~IDBIndexBackendImpl() { } +String IDBIndexBackendImpl::storeName() +{ + return m_objectStore->name(); +} + +static void openCursorInternal(SQLiteDatabase& database, IDBIndexBackendImpl* index, IDBKeyRange* range, unsigned short untypedDirection, bool objectCursor, IDBCallbacks* callbacks) +{ + // Several files depend on this order of selects. + String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ") + + (objectCursor ? "ObjectStoreData.value " : "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") + + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE "; + + bool leftBound = range && (range->flags() & IDBKeyRange::LEFT_BOUND || range->flags() == IDBKeyRange::SINGLE); + bool rightBound = range && (range->flags() & IDBKeyRange::RIGHT_BOUND || range->flags() == IDBKeyRange::SINGLE); + + if (leftBound) + sql += range->left()->leftCursorWhereFragment(range->leftWhereClauseComparisonOperator(), "IndexData."); + if (rightBound) + sql += range->right()->rightCursorWhereFragment(range->rightWhereClauseComparisonOperator(), "IndexData."); + sql += "IndexData.indexId = ? ORDER BY "; + + IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(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<SQLiteStatement> query = adoptPtr(new SQLiteStatement(database, sql)); + bool ok = query->prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + int indexColumn = 1; + if (leftBound) + indexColumn += range->left()->bind(*query, indexColumn); + if (rightBound) + indexColumn += range->right()->bind(*query, indexColumn); + query->bindInt64(indexColumn, index->id()); + + if (query->step() != SQLResultRow) { + callbacks->onSuccess(); + return; + } + + RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(index, range, direction, query.release(), objectCursor); + callbacks->onSuccess(cursor.release()); +} + +void IDBIndexBackendImpl::openObjectCursor(PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks) +{ + openCursorInternal(sqliteDatabase(), this, keyRange.get(), direction, true, callbacks.get()); +} + +void IDBIndexBackendImpl::openCursor(PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks) +{ + openCursorInternal(sqliteDatabase(), this, keyRange.get(), direction, false, callbacks.get()); +} + +static void getInternal(SQLiteDatabase& database, int64 id, IDBKey* key, bool getObject, IDBCallbacks* 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(database, sql); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + query.bindInt64(1, 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; + } + + if (getObject) + callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(0))); + else + callbacks->onSuccess(IDBKey::fromQuery(query, 0)); + ASSERT(query.step() != SQLResultRow); +} + +void IDBIndexBackendImpl::getObject(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks) +{ + getInternal(sqliteDatabase(), m_id, key.get(), true, callbacks.get()); +} + +void IDBIndexBackendImpl::get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks) +{ + getInternal(sqliteDatabase(), m_id, key.get(), false, callbacks.get()); +} + static String whereClause(IDBKey* key) { return "WHERE indexId = ? AND " + key->whereSyntax(); diff --git a/WebCore/storage/IDBIndexBackendImpl.h b/WebCore/storage/IDBIndexBackendImpl.h index 97c65f9..a98ed2a 100644 --- a/WebCore/storage/IDBIndexBackendImpl.h +++ b/WebCore/storage/IDBIndexBackendImpl.h @@ -49,9 +49,17 @@ public: // Implements IDBIndexBackendInterface. virtual String name() { return m_name; } + virtual String storeName(); virtual String keyPath() { return m_keyPath; } virtual bool unique() { return m_unique; } + virtual void openObjectCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>); + virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>); + virtual void getObject(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>); + virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>); + + IDBObjectStoreBackendImpl* objectStore() const { return m_objectStore.get(); } + private: IDBIndexBackendImpl(IDBObjectStoreBackendImpl*, int64_t id, const String& name, const String& keyPath, bool unique); diff --git a/WebCore/storage/IDBIndexBackendInterface.h b/WebCore/storage/IDBIndexBackendInterface.h index 0d1ea34..ff2316f 100644 --- a/WebCore/storage/IDBIndexBackendInterface.h +++ b/WebCore/storage/IDBIndexBackendInterface.h @@ -33,13 +33,23 @@ namespace WebCore { +class IDBCallbacks; +class IDBKey; +class IDBKeyRange; + class IDBIndexBackendInterface : public ThreadSafeShared<IDBIndexBackendInterface> { public: virtual ~IDBIndexBackendInterface() { } virtual String name() = 0; + virtual String storeName() = 0; virtual String keyPath() = 0; virtual bool unique() = 0; + + virtual void openObjectCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>) = 0; + virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>) = 0; + virtual void getObject(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>) = 0; + virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>) = 0; }; } // namespace WebCore diff --git a/WebCore/storage/IDBKey.cpp b/WebCore/storage/IDBKey.cpp index 6ae79ba..3eec36c 100644 --- a/WebCore/storage/IDBKey.cpp +++ b/WebCore/storage/IDBKey.cpp @@ -54,6 +54,22 @@ IDBKey::~IDBKey() { } +PassRefPtr<IDBKey> IDBKey::fromQuery(SQLiteStatement& query, int baseColumn) +{ + if (!query.isColumnNull(baseColumn)) + return IDBKey::create(query.getColumnText(baseColumn)); + + if (!query.isColumnNull(baseColumn + 1)) { + ASSERT_NOT_REACHED(); // FIXME: Implement date. + return IDBKey::create(); + } + + if (!query.isColumnNull(baseColumn + 2)) + return IDBKey::create(query.getColumnInt(baseColumn + 2)); + + return IDBKey::create(); // Null. +} + bool IDBKey::isEqual(IDBKey* other) { if (!other || other->m_type != m_type) @@ -73,22 +89,56 @@ bool IDBKey::isEqual(IDBKey* other) return false; } -String IDBKey::whereSyntax() const +String IDBKey::whereSyntax(String qualifiedTableName) const { switch (m_type) { case IDBKey::StringType: - return "keyString = ?"; + return qualifiedTableName + "keyString = ? "; case IDBKey::NumberType: - return "keyNumber = ?"; + return qualifiedTableName + "keyNumber = ? "; // FIXME: Implement date. case IDBKey::NullType: - return "keyString IS NULL AND keyDate IS NULL AND keyNumber IS NULL"; + return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL "; } ASSERT_NOT_REACHED(); return ""; } +String IDBKey::leftCursorWhereFragment(String comparisonOperator, String qualifiedTableName) +{ + switch (m_type) { + case StringType: + return "? " + comparisonOperator + " " + qualifiedTableName + "keyString AND "; + // FIXME: Implement date. + 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 ""; +} + +String IDBKey::rightCursorWhereFragment(String comparisonOperator, String qualifiedTableName) +{ + switch (m_type) { + case StringType: + return "(" + qualifiedTableName + "keyString " + comparisonOperator + " ? OR " + qualifiedTableName + "keyString IS NULL) AND "; + // FIXME: Implement date. + case NumberType: + return "(" + qualifiedTableName + "keyNumber " + comparisonOperator + " ? OR " + qualifiedTableName + "keyNumber IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND "; + 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 { diff --git a/WebCore/storage/IDBKey.h b/WebCore/storage/IDBKey.h index b9a0be7..3175e7e 100644 --- a/WebCore/storage/IDBKey.h +++ b/WebCore/storage/IDBKey.h @@ -73,8 +73,12 @@ public: return m_number; } + static PassRefPtr<IDBKey> fromQuery(SQLiteStatement& query, int baseColumn); + bool isEqual(IDBKey* other); - String whereSyntax() const; + String whereSyntax(String qualifiedTableName = "") const; + String leftCursorWhereFragment(String comparisonOperator, String qualifiedTableName = ""); + String rightCursorWhereFragment(String comparisonOperator, String qualifiedTableName = ""); int bind(SQLiteStatement& query, int column) const; void bindWithNulls(SQLiteStatement& query, int baseColumn) const; diff --git a/WebCore/storage/IDBKeyRange.cpp b/WebCore/storage/IDBKeyRange.cpp index 4088b34..6c612cc 100644 --- a/WebCore/storage/IDBKeyRange.cpp +++ b/WebCore/storage/IDBKeyRange.cpp @@ -71,6 +71,36 @@ PassRefPtr<IDBKeyRange> IDBKeyRange::bound(PassRefPtr<IDBKey> left, PassRefPtr<I return IDBKeyRange::create(left, right, flags); } +String IDBKeyRange::leftWhereClauseComparisonOperator() const +{ + if (m_flags & LEFT_OPEN) + return "<"; + + if (m_flags & LEFT_BOUND) + return "<="; + + if (m_flags == SINGLE) + return "="; + + ASSERT_NOT_REACHED(); + return ""; +} + +String IDBKeyRange::rightWhereClauseComparisonOperator() const +{ + if (m_flags & RIGHT_OPEN) + return "<"; + + if (m_flags & RIGHT_BOUND) + return "<="; + + if (m_flags == SINGLE) + return "="; + + ASSERT_NOT_REACHED(); + return ""; +} + } // namespace WebCore #endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBKeyRange.h b/WebCore/storage/IDBKeyRange.h index 5a426b7..4621a50 100644 --- a/WebCore/storage/IDBKeyRange.h +++ b/WebCore/storage/IDBKeyRange.h @@ -57,6 +57,9 @@ public: PassRefPtr<IDBKey> right() const { return m_right; } unsigned short flags() const { return m_flags; } + String leftWhereClauseComparisonOperator() const; + String rightWhereClauseComparisonOperator() const; + static PassRefPtr<IDBKeyRange> only(PassRefPtr<IDBKey> value); static PassRefPtr<IDBKeyRange> leftBound(PassRefPtr<IDBKey> bound, bool open = false); static PassRefPtr<IDBKeyRange> rightBound(PassRefPtr<IDBKey> bound, bool open = false); diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.cpp b/WebCore/storage/IDBObjectStoreBackendImpl.cpp index 86237de..e5f81ab 100755..100644 --- a/WebCore/storage/IDBObjectStoreBackendImpl.cpp +++ b/WebCore/storage/IDBObjectStoreBackendImpl.cpp @@ -279,64 +279,14 @@ void IDBObjectStoreBackendImpl::removeIndex(const String& name, PassRefPtr<IDBCa callbacks->onSuccess(); } -static String leftCursorWhereFragment(IDBKey::Type type, String comparisonOperator) -{ - switch (type) { - case IDBKey::StringType: - return "? " + comparisonOperator + " keyString AND "; - // FIXME: Implement date. - case IDBKey::NumberType: - return "(? " + comparisonOperator + " keyNumber OR NOT keyString IS NULL OR NOT keyDate IS NULL) AND "; - case IDBKey::NullType: - if (comparisonOperator == "<") - return "NOT(keyString IS NULL AND keyDate IS NULL AND 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 rightCursorWhereFragment(IDBKey::Type type, String comparisonOperator) -{ - switch (type) { - case IDBKey::StringType: - return "(keyString " + comparisonOperator + " ? OR keyString IS NULL) AND "; - // FIXME: Implement date. - case IDBKey::NumberType: - return "(keyNumber " + comparisonOperator + " ? OR keyNumber IS NULL) AND keyString IS NULL AND keyDate IS NULL AND "; - case IDBKey::NullType: - if (comparisonOperator == "<") - return "0 != 0 AND "; - return "keyString IS NULL AND keyDate IS NULL AND keyNumber IS NULL AND "; - } - ASSERT_NOT_REACHED(); - return ""; -} - void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks) { - String lowerEquality; - if (range->flags() & IDBKeyRange::LEFT_OPEN) - lowerEquality = "<"; - else if (range->flags() & IDBKeyRange::LEFT_BOUND) - lowerEquality = "<="; - else - lowerEquality = "="; - - String upperEquality; - if (range->flags() & IDBKeyRange::RIGHT_OPEN) - upperEquality = "<"; - else if (range->flags() & IDBKeyRange::RIGHT_BOUND) - upperEquality = "<="; - else - upperEquality = "="; - - // If you change the order of this select, you'll need to change it in IDBCursorBackendImpl.cpp as well. + // Several files depend on this order of selects. String sql = "SELECT id, keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE "; if (range->flags() & IDBKeyRange::LEFT_BOUND || range->flags() == IDBKeyRange::SINGLE) - sql += leftCursorWhereFragment(range->left()->type(), lowerEquality); + sql += range->left()->leftCursorWhereFragment(range->leftWhereClauseComparisonOperator()); if (range->flags() & IDBKeyRange::RIGHT_BOUND || range->flags() == IDBKeyRange::SINGLE) - sql += rightCursorWhereFragment(range->right()->type(), upperEquality); + sql += range->right()->rightCursorWhereFragment(range->rightWhereClauseComparisonOperator()); sql += "objectStoreId = ? ORDER BY "; IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection); diff --git a/WebCore/storage/IDBRequest.cpp b/WebCore/storage/IDBRequest.cpp index 3513c17..6fbda0e 100644 --- a/WebCore/storage/IDBRequest.cpp +++ b/WebCore/storage/IDBRequest.cpp @@ -153,13 +153,12 @@ void IDBRequest::timerFired(Timer<IDBRequest>*) Vector<PendingEvent> pendingEvents; pendingEvents.swap(m_pendingEvents); for (size_t i = 0; i < pendingEvents.size(); ++i) { - PendingEvent pendingEvent = pendingEvents[i]; - if (pendingEvent.m_error) { - ASSERT(!pendingEvent.m_result); - dispatchEvent(IDBErrorEvent::create(m_source, *pendingEvent.m_error)); + if (pendingEvents[i].m_error) { + ASSERT(!pendingEvents[i].m_result); + dispatchEvent(IDBErrorEvent::create(m_source, *pendingEvents[i].m_error)); } else { - ASSERT(pendingEvent.m_result->type() != IDBAny::UndefinedType); - dispatchEvent(IDBSuccessEvent::create(m_source, pendingEvent.m_result)); + ASSERT(pendingEvents[i].m_result->type() != IDBAny::UndefinedType); + dispatchEvent(IDBSuccessEvent::create(m_source, pendingEvents[i].m_result)); } } } diff --git a/WebCore/storage/IDBTransactionBackendImpl.cpp b/WebCore/storage/IDBTransactionBackendImpl.cpp index 51b33b2..51b33b2 100755..100644 --- a/WebCore/storage/IDBTransactionBackendImpl.cpp +++ b/WebCore/storage/IDBTransactionBackendImpl.cpp diff --git a/WebCore/storage/IDBTransactionBackendImpl.h b/WebCore/storage/IDBTransactionBackendImpl.h index fb57401..fb57401 100755..100644 --- a/WebCore/storage/IDBTransactionBackendImpl.h +++ b/WebCore/storage/IDBTransactionBackendImpl.h diff --git a/WebCore/storage/wince/DatabaseThreadWince.cpp b/WebCore/storage/wince/DatabaseThreadWinCE.cpp index d81145d..d81145d 100644 --- a/WebCore/storage/wince/DatabaseThreadWince.cpp +++ b/WebCore/storage/wince/DatabaseThreadWinCE.cpp diff --git a/WebCore/storage/wince/DatabaseThreadWince.h b/WebCore/storage/wince/DatabaseThreadWinCE.h index fafc791..1921cc1 100644 --- a/WebCore/storage/wince/DatabaseThreadWince.h +++ b/WebCore/storage/wince/DatabaseThreadWinCE.h @@ -21,8 +21,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef DatabaseThreadWince_h -#define DatabaseThreadWince_h +#ifndef DatabaseThreadWinCE_h +#define DatabaseThreadWinCE_h #include <wtf/Deque.h> #include <wtf/RefCounted.h> @@ -62,4 +62,4 @@ namespace WebCore { } // namespace WebCore -#endif // DatabaseThreadWince +#endif // DatabaseThreadWinCE_h diff --git a/WebCore/storage/wince/LocalStorageThreadWince.cpp b/WebCore/storage/wince/LocalStorageThreadWinCE.cpp index 8dcb902..90c4e89 100644 --- a/WebCore/storage/wince/LocalStorageThreadWince.cpp +++ b/WebCore/storage/wince/LocalStorageThreadWinCE.cpp @@ -80,4 +80,4 @@ void LocalStorageThread::performTerminate() m_timer.stop(); } -} +} // namespace WebCore diff --git a/WebCore/storage/wince/LocalStorageThreadWince.h b/WebCore/storage/wince/LocalStorageThreadWinCE.h index 300abb5..06e7d45 100644 --- a/WebCore/storage/wince/LocalStorageThreadWince.h +++ b/WebCore/storage/wince/LocalStorageThreadWinCE.h @@ -22,8 +22,8 @@ */ -#ifndef LocalStorageThreadWince_h -#define LocalStorageThreadWince_h +#ifndef LocalStorageThreadWinCE_h +#define LocalStorageThreadWinCE_h #include <wtf/Deque.h> #include <wtf/PassRefPtr.h> @@ -55,4 +55,4 @@ namespace WebCore { } // namespace WebCore -#endif // LocalStorageThreadWince_h +#endif // LocalStorageThreadWinCE_h |