summaryrefslogtreecommitdiffstats
path: root/WebCore/storage/IDBIndexBackendImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/storage/IDBIndexBackendImpl.cpp')
-rw-r--r--WebCore/storage/IDBIndexBackendImpl.cpp98
1 files changed, 98 insertions, 0 deletions
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();